Back to Blog
debuggingobservabilitysentryproduction

Most of My Frontend Debugging Doesn't Happen in DevTools

September 14, 20253 min read

Most of My Frontend Debugging Doesn’t Happen in DevTools

I closed a bug today that took me almost a full day. The part where I actually had DevTools open? Maybe four minutes. Four. The rest of the time was spent figuring out which bug I was even looking at. Nobody tells you that in production, DevTools is the victory lap, not the main event.

The screenshot in Slack

A PM drops a screenshot in a channel—no context, just “is this normal?” It’s a clipped dropdown. Could be anything: an untested viewport, a CSS regression, Safari being Safari, a rogue browser extension. The screenshot tells me there’s a bug. What I actually need is everything around it: the URL, the viewport, what the user did right before.

That’s why I’ve come around hard on tools like Sentry. The breadcrumbs are more valuable than the error tracking itself. The stack trace tells me where, but the last twenty user actions tell me how they got there—which is almost always the better question. Frontend errors aren’t like server errors; they’re weather. The same code runs in a hundred different environments, and you can fix it for 99% of users and still have a long tail you’ll never reproduce.

The sourcemap lesson

We once had production stack traces that looked like e.t.j is not a function for two months. Sourcemaps were uploading, the dashboard was green, everything looked fine. Turns out CI bumped the version number after the sourcemap upload, so all our maps were silently associated with the wrong release. Nobody noticed because nobody clicks into stack traces until there’s a fire. Now I deliberately throw an error in production right after launch and walk the full trail: did it show up, did it deminify, does the release match. It takes ten minutes and saves a future Tuesday.

The Safari 16.4 thing that broke me

One user couldn’t log in. They’d submit credentials and the page just sat there—no error, no network request, nothing. Everyone on the team tried to repro. Nothing. After a long email thread, we finally got the detail: iOS Safari 16.4, on cellular. Not wifi. On cellular, a third-party analytics script was being throttled by the carrier, and our login form had a Promise.all that included a promise from that script. It never errored, it just never resolved. Silent hang. No error tracking in the world would have caught that. The only signal was “user says it’s broken.”

That’s why “could not reproduce, closing” is the most dangerous phrase in any frontend tracker. Every ticket I’ve ever closed that way was a ticket where I gave up too early. Roughly half of them, in hindsight, were real bugs someone else hit later.

What I do now

  • When a screenshot arrives, I ask for the URL and a session replay before I open DevTools. Otherwise I just confirm whatever hypothesis already sounds good in my head.
  • If I have a stack trace, I read the breadcrumbs first. The “what happened before” matters more than the line that blew up.
  • If I can’t repro, I move the ticket to a “needs more info” state and keep it open. Closed tickets are pretend-fixed; open ones at least keep the problem visible.

Tools are great, DevTools is great, observability is great. But none of it replaces asking better questions about which bug you’re actually chasing. The answer is almost never in the stack trace. It’s in the metadata around it.