← All articles
🔍 TechniqueBeginner · 7 min read

Reading a Stack Trace Together: A Method for Debugging as a Team

Six small moves that turn the most intimidating part of an error message into a clear pointer at the line you need to change.

By Kishan Vaghani · Reviewed by Kajal Pansuriya

Stack traces are intimidating until you have a method. The most common way one lands in your day is not alone at your own desk: a teammate pastes a wall of red into a shared chat or a live session and asks, "any idea?" Now two of you are staring at the same unfriendly text. The good news is that a stack trace is a precise instrument that, read properly, points within seconds at the line of code you need to change — and two people reading it together get there faster than one.

The method below is six small moves. None of them are clever; together they make any stack trace — JavaScript, Python, anything — readable. The same routine applies whether you are debugging solo or looking at a trace a colleague just dropped in front of you, so we will walk the six steps first and then show how to split them between two readers in a shared session.

What a stack trace is actually telling you

When an error is thrown, the runtime captures the chain of function calls that led to the throw and prints them in order from most-recent to least-recent. The top frame is the function that actually threw. Each frame below it is the function that called the one above it. The bottom frame is wherever the program started — a request handler, a button click, a script entry point.

The trace is not the error. The error is the message at the top, usually one short line. The trace is the breadcrumb path the runtime walked to get there. Read the message first; read the trace second.

The six-step routine

Step 1. Read the error message at the top

The first line of the output usually contains everything you need to identify the category of bug: TypeError, ReferenceError, ConnectionRefusedError, ValueError. Read it twice. The category alone tells you whether you are looking at a typo, a logic bug, a missing dependency, or an infrastructure failure.

Step 2. Read the second line — the specific cause

The second line names the specific value that triggered the error. Cannot read properties of undefined (reading 'name') tells you which property was missing. list index out of range tells you the access was past the end of an array. Get the specific value into your head before looking at any frame.

Step 3. Find the first frame in your own code

The top frame is often in a library — node_modules, the React runtime, the Firebase SDK. That is not where the bug lives. The bug lives at the boundary between your code and the library. Scan down the trace until you find the first file path that points at your source files. That frame is the one to read carefully. On ShareCode, whose editor runs on React and the Firebase SDK, the traces we chase most often bury our own first frame a dozen lines down under SDK internals — finding that frame is consistently the fastest move.

TypeError: Cannot read properties of undefined (reading 'id')
    at applyFilters (node_modules/react-query/lib/...)   ← library
    at QueryCache._notify (node_modules/react-query/...) ← library
    at QueryObserver.<anonymous> (node_modules/...)      ← library
    at UserList (src/components/UserList.tsx:42)         ← YOUR FRAME
    at renderWithHooks (node_modules/react-dom/...)
    at mountIndeterminateComponent (...)

In this trace, the bug is at line 42 of UserList.tsx. The frames above it are how the library got there; the frames below are how React got to your component. You only need to look at line 42.

Step 4. Open the named file at the named line

Open the file. Look at the exact line. Find the value that the error message named. In our example, line 42 of UserList.tsx is reading .id off something that turned out to be undefined. The next question is: where did that something come from?

Step 5. Walk upstream from the failing line

The failing line is the point of impact, not the source. Look at where the variable was assigned. Is it the result of an array access that might have returned undefined? Is it a prop that the parent component might have failed to pass? Is it a fetch response that might have come back empty? Walk one step upstream at a time until you find the place where the value first became wrong.

Step 6. Reproduce, then fix one thing

Before changing code, reproduce the failure. Run the exact path that triggered the trace and confirm the same error appears. Then change exactly one thing — add a null check, fix the upstream assignment, correct the prop type — and run the same path again. If the error is gone, you fixed it. If a different error appears, you have made progress: a new error usually means the original bug is fixed and a downstream bug has been exposed.

Worked example

Here is the same routine applied to a real-shaped trace from a Python service:

Traceback (most recent call last):
  File "/app/server.py", line 88, in handle_request
    return self.process(payload)
  File "/app/service.py", line 41, in process
    user = self.users[payload["user_id"]]
KeyError: 'user_id'
  1. Step 1. KeyError — a dictionary lookup failed. This is a logic bug, not a typo or infrastructure issue.
  2. Step 2. Specific value: 'user_id'. The key being looked up was user_id and it was not present in whatever dictionary this is.
  3. Step 3. First frame in our code: line 41 of service.py. Both frames are ours here, so the boundary is thepayload["user_id"] access.
  4. Step 4. Line 41 reads user_id from payload. payload is missing that key.
  5. Step 5. Walk upstream. payload comes from the request body in handle_request. The bug is either a client sending the wrong field name (validation issue) or our code expecting a field that the API contract does not require (assumption issue).
  6. Step 6. Reproduce by sending a request without user_id, then fix one thing — add validation at the request boundary that rejects the request with a clear 400 response instead of crashing with a KeyError.

Reading a trace together

The scenario that started this post is the everyday one: a teammate pastes a trace into a shared session and says "any idea?" The instinct is for both people to scroll the same wall of text in parallel and narrate over each other. Splitting the work is faster. One person reads top-down for the throw site — the error message and the first frame that actually raised it. The other follows the chain downward, tracing any Caused by: sections or the async boundaries that stitch one trace onto another, so the group sees both the impact point and the path that led there at the same time.

The move that makes this concrete is sharing line numbers, not screenshots. Paste both the trace and the offending file into the same editor so everyone is looking at the same line 42, not a description of it. The senior engineer's real contribution is rarely a flash of insight — it is pointing at the first line that is in your code, past the framework frames everyone else was still reading. Once that line is named, the rest of the routine (open it, walk upstream, reproduce, fix one thing) runs the same as it does solo.

This is exactly what ShareCode is for. Drop the trace and the file into a code space, share the URL — no install, no signup — and both people are in the same document with live cursors. When you point at the offending line, the other person sees your cursor land on it, with no screen-share lag and no "scroll up a bit, no, the other one." Two readers, one shared line, the six-step method between you.

The habit that compounds

The first dozen stack traces you read carefully will feel slow. The next hundred will feel automatic. After a year of running this routine on every error you encounter, you will be reading traces faster than the runtime can finish printing them, and the intimidation factor will be gone for good. The discipline that gets you there is small but non-negotiable: never paste a trace into a search engine before you have read it yourself.

Related reading

Reading stack traces is one of the compounding skills covered in the engineering-foundations topic. For the broader JavaScript debugging toolkit, the JavaScript debugging guide covers conditional breakpoints, async stack traces, and the DevTools moves that go beyond reading the trace itself.

References & Sources

The primary sources, specifications, and documentation behind this article. Each link opens in a new tab.

  1. Error.prototype.stack

    MDN contributors · MDN Web Docs

    Defines the JavaScript stack string this post teaches you to read, including how frame format differs across engines.

    developer.mozilla.org
  2. Stack trace API

    V8 Team · V8

    Authoritative source on how V8 (Chrome, Node.js) builds the trace, plus the zero-cost async stack traces referenced in the FAQ.

    v8.dev
  3. traceback — Print or retrieve a stack traceback

    Python Software Foundation · Python Documentation

    The reference for the Python traceback format used in the worked KeyError example.

    docs.python.org
  4. Errors and Exceptions

    Python Software Foundation · Python Documentation

    Explains the 'most recent call last' ordering and the caret markers that step 1 of the routine relies on.

    docs.python.org
  5. Debug your original code instead of deployed with source maps

    Chrome DevTools Team · Chrome for Developers

    Backs the production-trace FAQ: source maps translate minified frames back to the original file and line.

    developer.chrome.com

About the writers

Author

Kishan Vaghani

Founder & Lead Engineer, ShareCode

Founder of ShareCode. Writes the engineering deep-dives on this site — WebRTC, Firebase Auth, real-time sync, and the production patterns behind the editor itself.

Real-time collaboration & CRDTsWebRTC & low-latency mediaFirebase authentication & security rulesNext.js & full-stack JavaScript
Reviewed by

Kajal Pansuriya

Developer Educator, ShareCode

Developer educator at ShareCode. Writes the tutorial track — Python, JavaScript debugging, coding-interview prep, and the everyday code-quality habits that hold up in real codebases.

Python fundamentals & teaching beginnersJavaScript debugging & DevToolsCoding-interview preparationClean code & code review

Stuck on a trace you can't crack?

Paste the trace and the surrounding code into a code space, share the link with a colleague, and walk through the six-step routine together. Most stuck traces unstick within the first three steps when a second reader is in the document.

Open a code space