What does a Sentry SDK capture when an unhandled exception escapes, and what makes the stack trace readable in minified production code?
answer
- more than just the stack trace
- what happened just before the crash
- scope: user, tags, release, request
- generated frames need a mapping artifact
- uploaded at build, matched at ingest
basics
~20 sA Sentry SDK sends the exception type, message and stack trace plus the surrounding scope: request, user, tags, release and a trail of breadcrumbs. Minified or compiled frames stay unreadable until matching source maps or symbol files are uploaded.
solid answer
~50 sA Sentry SDK's global error handlers turn the escaping exception into an **event** and post it to the project identified by the DSN. The event carries the exception type and value with a stack trace per chained cause, the current **scope** -- user, tags, `release`, `environment`, request data -- and **breadcrumbs**: a bounded, time-ordered trail of the log calls, HTTP requests, navigations and clicks that preceded the failure, which is usually what tells you *how* the user got there. Production code is minified, obfuscated or compiled, so those frames point at generated output. Sentry symbolicates them only if the matching artifact -- a source map, a dSYM, an R8 mapping file -- was uploaded to the project at build time and can be matched to the event, either by release or by an embedded debug ID.
code
javascript · 13 linesSentry.init({
dsn: process.env.SENTRY_DSN,
release: process.env.SENTRY_RELEASE,
environment: "production",
maxBreadcrumbs: 50,
});
Sentry.setUser({ id: permitHolderId });
Sentry.setTag("permit_type", "resident");
Sentry.addBreadcrumb({
category: "permit",
message: "renewal form submitted",
});go deeper
Be ready to name what a Sentry issue shows beyond the message: the stack trace, the user and request context, the release, and the breadcrumb trail. Knowing that minified code needs uploaded source maps before the frames mean anything is expected.
Explain the mechanics: global handlers build the event, the active scope supplies user, tags and release, and integrations fill the breadcrumb buffer automatically. Be able to say how symbolication matches an event's frames to an artifact uploaded at build time.
Show that you have debugged the quiet failures -- unreadable frames because the release or debug ID did not match, breadcrumbs full of framework noise and empty of domain steps, personal data reaching a third party through request bodies. Say where you scrub and why there.
Own it as a standard: one release identifier produced by the build and consumed by the SDK, artifact upload wired into every pipeline, and an agreed rule about what context may leave the estate at all. Be able to argue what that consistency costs and what it buys.
## What the SDK builds when an exception escapes A Sentry SDK installs itself into the runtime's failure paths -- the global unhandled-exception and unhandled-rejection handlers, plus framework middleware and the integrations you enable. When an exception escapes your code, the SDK does not simply forward the message. It assembles an **event**: a JSON document posted to the ingest endpoint named by the project's **DSN**, the client key you pass to `Sentry.init`. The event has layers, and each layer answers a different question. | Layer | What it carries | Answers | | --- | --- | --- | | Exception | type, value, and a stack trace for each chained cause | what broke | | Scope | user, tags, contexts, `release`, `environment` | who and where | | Breadcrumbs | an ordered trail of recent activity | how they got there | | Request | URL, method, headers, query string | what was being served | | SDK and runtime | SDK name and version, OS, runtime, device | what it was running on | **Breadcrumbs** are the layer engineers underestimate. Each breadcrumb is a small record -- a category, a message, a level, a timestamp and optional structured data -- appended to a bounded ring buffer on the current scope; `maxBreadcrumbs` sets the bound and the major SDKs default it to one hundred. You rarely write them by hand: the built-in integrations record console and log calls, outgoing HTTP requests, navigation and route changes, query hooks and UI clicks. The moment an exception is captured, the buffer is frozen onto the event. That is why a Sentry issue can tell you that the user searched, opened a permit renewal, submitted it, received a 502 from an upstream, and *then* hit the error -- a sequence no stack trace contains. Domain steps you care about you add yourself with `Sentry.addBreadcrumb(...)`. **Scope** is the other half. `Sentry.setUser(...)`, `Sentry.setTag(...)` and `Sentry.setContext(...)` attach data to the currently active scope, and every event captured under that scope inherits it. The distinction that matters: **tags are indexed**, so they are what you search and filter issues by, while contexts are arbitrary structured data you read once you already have the event open. ## Why the frames are unreadable, and what makes them readable Almost nothing runs in production the way it was written. A browser bundle is minified and mangled, so `handleRenewal` is now `t` and forty modules share one line. An Apple binary is compiled and stripped. Android bytecode is shrunk and obfuscated. The frames that reach Sentry are honest -- file, line, column -- but they describe generated output, not your source. Turning them back into source positions is **symbolication**, a server-side lookup that needs two things: 1. **The mapping artifact must be in the project.** Source maps for JavaScript, dSYM files for Apple platforms, an R8 or ProGuard mapping file for Android, PDB or DWARF data for native code. Your build produces them and uploads them to Sentry, typically with `sentry-cli` or a bundler plugin. 2. **This event's frames must be matchable to that artifact.** Classically the match runs through the release: the SDK reports `release` at runtime, the upload happened under the same release, and the artifact names line up with the frame paths. Modern JavaScript tooling instead embeds a **debug ID** in both the bundle and its map, so the match survives hashed filenames and CDN paths. The failure is silent. Nothing errors; you simply get an issue whose top frame reads `t (main.4f1c9e.js:1:48213)`. Worse, it degrades grouping as well, because the default grouping reads function and module names from those same frames -- two unrelated bugs can collapse into one issue when every symbol is a single letter. One more frame-level detail is worth knowing: the `in_app` flag marks whether a frame is your code or a dependency. Sentry expands in-app frames by default and the default grouping leans on them, so wrong in-app rules both hide the interesting line and blur unrelated issues together. ## Practical consequences - An event with no user, no release and no breadcrumbs is a stack trace with extra latency. The setup work is what makes the tool worth having. - Breadcrumbs and request data are the likeliest route for personal data to reach a third party. Redact in the SDK's before-send and before-breadcrumb hooks, before the event leaves the process, and treat the send-default-PII option as a deliberate decision rather than something you inherit. - Uploading mapping artifacts at build time and setting the same release in the SDK at runtime are one change, not two. Half of it does nothing at all, quietly, and you find out during an incident. - Breadcrumbs are cheap but not free: a chatty integration can fill the whole buffer with framework noise and push the three domain steps that mattered off the end of it.
- Your browser issues still show frames like `t (main.4f1c.js:1:52310)` even though the build uploads source maps. What do you check?Check that the artifacts can be matched to this event. The release the SDK reports at runtime must be the release the maps were uploaded under, or the bundle and its map must both carry the same debug ID. Then check that the uploaded map covers the exact file the frame names -- a CDN path, a rebuilt bundle, or a second deploy under a reused release identifier all break the match while nothing reports an error.
- Which parts of a Sentry event most often leak personal data, and where do you strip it?Request headers and bodies, URLs carrying identifiers in the query string, the user context, and breadcrumbs that logged a payload. Strip inside the SDK before the event leaves the process -- the before-send hook for events and the before-breadcrumb hook for the trail -- rather than relying on server-side scrubbing, and treat the send-default-PII option as a decision you made rather than a default you inherited.
- What does the `in_app` flag on a stack frame change?It marks whether a frame belongs to your code or to a dependency. Sentry expands in-app frames by default and the default grouping leans on them, so a wrong in-app rule both buries the interesting line under framework frames and makes unrelated errors group into one issue.
The stack trace is the photograph of the crash; the breadcrumbs are the dashcam footage of the two minutes before it.
saying these in an interview costs you the question
- Says Sentry sends only the exception message and stack trace
- Thinks every breadcrumb must be written by hand in application code
- Expects Sentry to de-minify frames with no uploaded artifact
- Uploads source maps but never sets a matching release in the SDK
- Assumes any attached context is searchable the way a tag is
- Sends request bodies and user emails without considering PII