DEV Community

Vladimir Elchinov for Session Replay

Posted on

Your Error Tracker Shows Zero Crashes Because It Lives Inside the Thing That Crashed

Open your error dashboard and filter for renderer crashes. You will find none. That is not because your pages do not crash.

Chrome shipped 52 security fixes yesterday, four of them critical, and the classes read: memory corruption, use after free, improper input validation. Those do not throw an exception. They take the process down. The tab goes grey, or it reloads itself, or it simply stops being a page.

The structural problem, not a missing feature

Everything you installed to tell you about a failure runs in the page. When the page is the casualty, so is the reporter. window.onerror did not stay quiet; it was never called, because nothing was left running to call it.

MDN says this outright about the browser's own crash report, which cannot be picked up by a ReportingObserver for the plainest possible reason:

the reports are only generated when the browser crashes, at which point the observer code isn't available to run.

So there is no listener for this. Not a try/catch, not an unhandledrejection handler, not a ReportingObserver. The event you most want is the one your page cannot be awake for.

What works is a header, not a script

The only route is the browser reporting it afterwards, on its own, out of band. That is one response header:

Reporting-Endpoints: crash-reporting="https://example.com/reports"
Enter fullscreen mode Exit fullscreen mode

No bundle change, nothing to initialise, nothing that can fail to load. That is the point: it has to work when your JavaScript does not exist.

Three things that will make you think it is broken

This is the part worth knowing before you wire it up, because each one looks like failure.

It is slow on purpose. Chrome's documentation: "Reports are delivered out-of-band from your site", and reports are "sent with a delay" of up to a minute so the browser can batch them. The browser "captures, queues, and sends them automatically at a suitable time". Crash a tab, watch your endpoint, see nothing, conclude it does not work: that is the obvious mistake and you will make it within the first five minutes.

A non-secure endpoint is dropped in silence. MDN: "Non-secure endpoints are ignored." No console warning, because there is no console to warn in.

Nothing in your code proves it is on. It is a header, so it does not appear in your bundle, your dependency list or your init path. The only way to know it is live is to look at a response, which is also the only way to notice that a proxy or a CDN stripped it.

What actually arrives

A POST with Content-Type: application/reports+json. Each report carries age in milliseconds since it was generated, plus type, url, user_agent, and a body whose shape depends on the type.

age is the field that earns its place. The report arrives late by design, so the arrival time is not the incident time, and age is what converts one into the other. Log the arrival and you will put the crash a minute after the thing that caused it.

For a crash, the field to read is reason. MDN documents two values:

  • oom: the page ran out of memory.
  • unresponsive: the page was killed due to being unresponsive.

Why that one field is the whole diagnosis

Those are different bugs with different fixes. One is a leak or an allocation you did not bound. The other is work on the main thread that never yielded.

They are also the exact distinction the person in front of the problem cannot make for you. "It crashed" and "it froze so I closed it" are the same sentence to them, chosen by mood rather than by mechanism, and the report arrives with that choice already baked in. reason is measured instead of typed, which is why it is worth more than the paragraph describing it.

The thing to do, and the thing to ask

Set the header. It costs one line and it covers the case your in-page instrumentation is structurally unable to reach.

Then, when somebody says a tab died, ask one question before anything else: did the whole tab go, or did the page stop responding first? You are asking them to separate oom from unresponsive without using either word, and it splits the problem in half before you have started looking.

A zero on that dashboard was never a fact about your software. It was a fact about where you put the instrument.

Top comments (0)