Open the first file your team wrote
Chrome, Node, Java, and C# print the newest call on top. Python prints the newest call at the bottom. People who live in one of those printers read the other one backwards for years.
The dump sitting in Slack starts with node_modules/express/lib/router/layer.js. Half the room opens Express. The bug lives six frames down in lookup.js, on a property access against a missing host. Framework frames are cover. Walk past them until a path under the application repo shows up.
A stack trace formatter does one job here. Split each frame into function, file, and line. Dim the vendor ones. Pin the first application call so nobody argues about which line to open.
The dump never runs. Sourcemaps stay unresolved. Native frames stay opaque.
This desk reads the characters you paste. A webpack bundle pointing at line 1, column 1 stays at line 1, column 1. Apply the map in DevTools or in the error tracker before you argue about the line number. Async gaps stay missing. The runtime dropped those frames before the dump reached you.
- Read the exception type before any frame.
TypeError,KeyError, andNullPointerExceptionalready name the class of mistake. - Find the first path under the application repo. That is the file to open, not the first line of the dump.
- Ignore
webpack://until a sourcemap exists. Line 1:1 on a minified bundle is a fingerprint, not a location. - If the application frame is a one-line wrapper, step into the caller. Wrappers exist to make dumps look tidy. They hide the real call.
Printers disagree on direction
Same crash. Different paper. The formatter has to know which printer wrote the dump, or the pin lands on the wrong end.
| Printer | Newest call | Where the exception sits | A frame looks like |
|---|---|---|---|
| V8 (Chrome, Node) | Top | First line | at resolveHost (lookup.js:23:45) |
| Firefox | Top | First line | resolveHost@https://toolexe.com/assets/lookup.js:23:45 |
| Java / C# | Top | First line, then Caused by or inner exception blocks below | at com.toolexe.lookup.HostResolver.resolve(HostResolver.java:23) |
| PHP | Top | First line, sometimes repeated as thrown in at the end | #0 /opt/toolexe/app/Lookup.php(23): App\Lookup->resolveHost() |
| Python / Ruby | Bottom | Last line | File "/opt/toolexe/app/lookup.py", line 23, in resolve_host |
| Go | Top of each goroutine | panic: line, then one block per goroutine | Function on one line, file.go:23 on the next |
Auto reads those patterns and picks a printer. Mixed dumps fool it. A Python traceback pasted under a Node worker log will score as Python if a File "...", line line is present. Switch the printer by hand when the pin looks wrong.
Skip vendor, then come back
Most nights the first application frame is the right door.
Some nights the defect lives in the library. A Spring release that throws on a null older builds swallowed. A Laravel middleware order after an upgrade. A Go standard library change in net/http. Skip vendor first. If the application frame looks innocent, walk back into the library with the version number in hand.
Vendor here means a path match, not a verdict. node_modules, vendor/, site-packages, org.springframework, Microsoft.AspNetCore, node:internal, and java.base all dim. A first-party package published under a vendor-shaped folder will dim too. Unhide the frames and read the path before you file a ticket against Express.
Java truncates with ... 32 more. Those missing frames are the ones you need on a deep call into Spring. Reproduce under a debugger, or raise -XX:MaxJavaStackTraceDepth, when the dump stops at a framework adapter.
webpack:// is not a folder on disk
Bundlers rewrite locations. The dump then names a virtual path, a hash, or a single-letter function. Opening that path in the repo does nothing, because the file never existed on disk in that shape.
This page will not apply a sourcemap. There is no upload, no .map picker, and no attempt to guess sourcesContent. Error trackers such as Sentry apply the map on ingest. Chrome DevTools applies the map when the file was served with a sourceMappingURL. Paste the mapped dump if you already have one. Paste the raw dump if you do not, and treat line 1:1 on a .min.js as a dead end until a map exists.
Single-letter names, .min.js, and bundle.js trip a minified warning on the pin. The warning is a prompt to go get the map, not a claim about the code.
If the dump is still on the clipboard, paste it in the desk above. Auto picks the printer in most cases. Switch the language by hand when Node frames sit under a Python traceback, which happens in mixed workers.
Home directories ride along
/home/deploy/. C:\Users\build\. /Users/ plus a laptop login. Those prefixes survive into tickets, screenshots, and Slack threads. The desk runs in the tab, so the dump is not uploaded. The paste still leaks a username the moment formatted output lands in a public issue.
Redact the prefix before the ticket leaves the team. Keep the filename and the line. Drop the account folder. The bug report template generator is the right next desk when the formatted frames need to travel with reproduction steps, because a raw dump in the ticket body is how home directories escape.
A leak flag appears on the pin when a frame path matches a user folder. The flag does not redact for you. Copy, then strip.
Three ways to read the same dump
- Pinned cards
- Each frame is a block with function, short name, and full path. The application frame to open stays in a pin above the list. Use this when you are still hunting.
- One line each
- Index, function, file:line. Use this when the dump is long and you already know the pin. Copy is cleaner in this mode because each frame is one line of text.
- Field grid
- Function, file, line, column, and full path as labeled fields. Use this when you are writing the location into a ticket and you do not want to re-parse a compact line by eye.
Hide vendor frames once the pin looks right. The counts at the bottom still include hidden frames, so a dump with 4 application frames and 40 Express frames still reads as 44.
Frames this desk will not invent
Runtimes drop frames. The formatter has nothing to reconstruct them from.
- Async gaps. A
Promiserejection in JavaScript, or a Pythonasynctask, often prints the await site without the callback that queued the work. The missing caller is gone. - Native frames.
Native Method,node:internal, and Go runtime lines name a binary, not a file you will open in the editor. - Truncation. Java
... n more, PHP dumps cut by the logger, and systemd journals that wrap at 2 KB. What is missing stays missing. - Inner causes. Java
Caused by:and C# inner exceptions are parsed as extra exception lines plus their frames. PythonThe above exception was the direct causeis kept as text. The pin still prefers the newest application frame of the selected printer, which is the right default and the wrong one when the outer wrapper is yours and the inner exception is the library. - Language the chips do not name. Ruby, Rust, Kotlin, and Swift dumps either match a cousin (Kotlin often parses as Java) or produce zero frames. Pick the cousin, or paste the frames into a ticket as-is.
A dump with no matching frames is not a failed paste. The first line still shows as the exception. The rest of the text did not match a known frame pattern for the selected printer. Switch printer, or load a known dump above to see what a match looks like.
You have a file. Now what?
Open the pinned file at the pinned line. If the file is JavaScript and the line looks like a missing brace, the JavaScript syntax checker compiles the snippet without running it. A parse error and a TypeError are different desks. Mixing them wastes the next hour.
If the same exception repeats across requests, stop formatting one dump. Take the log file to the error log analyzer and count the signature. One formatted crash is a location. A counted signature is a priority.
Need a trail of what you already tried? The debug session recorder stores notes against the incident so the next person does not rerun the same dead end. Live console noise during a reproduce belongs on the real-time error checker, which is a different question from reading a dump that already happened.
