1(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[4036],{7228:function(e,n,s){(window.__NEXT_P=window.__NEXT_P||[]).push(["/blog/one-trick-debugger",function(){return s(7579)}])},7579:function(e,n,s){"use strict";s.r(n),s.d(n,{__N_SSG:function(){return o},meta:function(){return a}});var t=s(5893),i=s(1151),r=s(2256),o=!0;let a={title:"âOne Trickâ to Save Time Integrating with Buggy Proprietary Apps",summary:"Finding a use for the browser dev tools that I never expected",published:"18 Apr 2025",heroImage:"/images/blog/214/hero.webp",openGraphImage:"/images/blog/214/opengraph.png",heroTheme:"lightOnDark",order:214},l=e=>(0,t.jsx)(r.j0,Object.assign({meta:a},e));function h(e){let n=Object.assign({p:"p",code:"code",em:"em",h3:"h3",a:"a",img:"img",ul:"ul",li:"li",strong:"strong",ol:"ol"},(0,i.ah)(),e.components);return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(n.p,{children:["Maybe Iâm old-fashioned, but I rarely use a debugger when programming. Usually, chucking in some ",(0,t.jsx)(n.code,{children:"print"})," statements to test my assumptions does the job."]}),"\n",(0,t.jsxs)(n.p,{children:["Iâve recently found a surprising use for this dev tool; ",(0,t.jsx)(n.em,{children:"debugging other peopleâs code. In particular, 2 checkboxes"})," are usually enough to find exactly what Iâm looking for, even in megabytes of minified, proprietary code. This technique is simpler than I thought, so Iâll share it below:"]}),"\n",(0,t.jsx)(n.h3,{children:"Setting the scene"}),"\n",(0,t.jsxs)(n.p,{children:["I first used this while building Webflow integrations at ",(0,t.jsx)(n.a,{href:"https://www.relume.io",children:"Relume"}),". Our Webflow features mostly worked via the clipboard; weâd write the data in Webflowâs internal, undocumented format, and then the user would paste it into the Webflow app. Sometimes, our data would crash Webflowâs frontend, but it wasnât clear why."]}),"\n",(0,t.jsx)(n.p,{children:"That scenario felt specific to Relume, so I was reluctant to share it. However, recently I ended up using the same technique in a wildly different situation."}),"\n",(0,t.jsxs)(n.p,{children:["For ",(0,t.jsx)(n.a,{href:"https://www.xintra.org/",children:"XINTRA Labs"}),", I was building a Microsoft Entra ID SAML Federation Provider, whatever that means. As part of that, I needed to upload an SAML-formatted XML file to the Entra dashboard. But when I uploaded the file, all I got was a generic error message:"]}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.img,{src:"/images/blog/214/image.webp",alt:"Entra error message"})}),"\n",(0,t.jsx)(n.p,{children:"Initially, I opened the browser dev tools and resubmitted the file. I thought the parsing would be done by the backend, but saw no network request made. That left only 1 option; the Entra ID frontend parsed the file. A frontend error calls for the JS debugger:"}),"\n",(0,t.jsx)(n.h3,{children:"Finding a bug in somebody elseâs frontend"}),"\n",(0,t.jsx)(n.p,{children:"So I was in this situation:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"I could reproduce a bug reliably (uploading a file)"}),"\n",(0,t.jsx)(n.li,{children:"But I didnât get a helpful error"}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["To reveal the secrets, I opened my browserâs ",(0,t.jsx)(n.strong,{children:"Debugger"})," (caused the â",(0,t.jsx)(n.em,{children:"Sources"}),"â tab in Chrome) and checked 2 options: ",(0,t.jsx)(n.strong,{children:"Pause on Uncaught Exceptions"})," and ",(0,t.jsx)(n.strong,{children:"Pause on Caught Exceptions"}),"."]}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.img,{src:"/images/blog/214/checkboxes.webp",alt:"Chrome DevTools checkboxes"})}),"\n",(0,t.jsx)(n.p,{children:"After reproducing the bug, the debugger paused at exactly the code that was causing the error:"}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.img,{src:"/images/blog/214/image%201.webp",alt:"Chrome DevTools debugger pause"})}),"\n",(0,t.jsx)(n.p,{children:"Here, I can see 3 critical things:"}),"\n",(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:["The step where the error originates (finding ",(0,t.jsx)(n.code,{children:"EntityDescriptor"}
1)," XML element)"]}),"\n",(0,t.jsxs)(n.li,{children:["The variables of interest (",(0,t.jsx)(n.code,{children:"t"})," - the parsed XML file)"]}),"\n",(0,t.jsxs)(n.li,{children:["Using Chromeâs console, I can poke further in the variables (running ",(0,t.jsx)(n.code,{children:"t.childNodes[2].nodeName"})," to verify that my XML fileâs ",(0,t.jsx)(n.code,{children:"EntityDescriptor"})," is in fact loaded)"]}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.img,{src:"/images/blog/214/image%202.webp",alt:"Chrome DevTools console usage"})}),"\n",(0,t.jsxs)(n.p,{children:["In this case, the error is obvious. The Entra portalâs XML parsing does not handle XML namespaces irrespective of aliases. To workaround Entraâs issue, I needed to write my XML file with specific namespace aliases (",(0,t.jsx)(n.code,{children:"md:"})," instead of ",(0,t.jsx)(n.code,{children:"ns0:"}),")."]}),"\n",(0,t.jsx)(n.p,{children:"Spending a few minutes with the debugger saved a lot of time staring at non-existent documentation or even submitting a support request."}),"\n",(0,t.jsx)(n.h3,{children:"What about bigger apps?"}),"\n",(0,t.jsx)(n.p,{children:"The bug isnât always this obvious. For instance, when investigating Webflow crashes during my work at Relume, I had to undertake some additional steps:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Parts of Webflowâs coded follow the idiom of âAsk Forgiveness, Not Permission.â So my debugger would repeatedly pause in code that used exceptions for control flow; pausing before I even started reproducing the bug. That is easily fixed by right clicking the line number and selecting â",(0,t.jsx)(n.em,{children:"Never Pause Here"}),"â then pressing ",(0,t.jsx)(n.code,{children:"F8"})," or â",(0,t.jsx)(n.em,{children:"Resume script execution"}),"â."]}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.img,{src:"/images/blog/214/image4.webp",alt:"Chrome DevTools Never Pause Here"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Webflowâs code is minified. Make sure that â",(0,t.jsx)(n.em,{children:"Automatically pretify minified sourcesâ"})," is enabled. Chrome will prompt you the first time, but you can change the option in the DevToolâs settings later too:"]}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.img,{src:"/images/blog/214/image%203.webp",alt:"Chrome DevTools settings"})}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Webflowâs code was more abstract than Entra portal. The code where the debugger paused was less informative about the issue. However, looking at the ",(0,t.jsx)(n.em,{children:"Local"})," Variables in the ",(0,t.jsx)(n.em,{children:"Scope"})," panel, I could see a UUID. Cross-referencing with my input, it was clear that Iâd accidentally created a cycle in what was supposed to be a tree:"]}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.img,{src:"/images/blog/214/compare.webp",alt:"ChromeDev Tools scope compared to JSON doc"})}),"\n",(0,t.jsx)(n.h3,{children:"Conclusion"}),"\n",(0,t.jsxs)(n.p,{children:["Next time youâre battling some baffling behaviour on a web app, I hope this strategy can help you get to the root cause. Try using ",(0,t.jsx)(n.em,{children:"Pause on Caught Exceptions"})," to track down errors where the web appâs UI is hiding information you need to fix it."]}),"\n",(0,t.jsx)(n.p,{children:"Do you have other tips & tricks for building integrations with spottily documented services? If so, Iâd love to hear them below."}),"\n"]})}n.default=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return(0,t.jsx)(l,Object.assign({},e,{children:(0,t.jsx)(h,e)}))}}},function(e){e.O(0,[8695,2256,9774,2888,179],function(){return e(e.s=7228)}),_N_E=e.O()}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.