You're Reading the Stack Trace Wrong

- Python tracebacks read bottom-up: the last line is the error type, the frame above it is the exact crash location
- Java stack traces are top-down: the first frame after the exception line is where execution blew up
- Error type names (IndexError, NullPointerException, RecursionError) tell you the bug category before you read a single message word
- The reported line is not always the buggy line: SyntaxErrors point one line past the problem, NPEs point to the crash site not the null source
- Library frames are noise: scan for the first frame referencing your own file and start there
- In an interview, make one change at a time and narrate your hypothesis out loud before touching the code
You run your code. A wall of red text appears. Your brain glazes over within 0.3 seconds. You scroll to the top, skim for a word you recognize, find nothing, and start changing lines at random until it either works or you close the laptop and go for a walk.
That instinct also explains why your interviewer ends up quietly typing "seemed uncertain when debugging" on your scorecard.
Stack traces and error messages are not noise. They're structured documents with a specific reading order. Once you know the order, most bugs announce their location and category in the first five seconds.
Reading order: bottom first, error type second, your file third, one fix only.
Read From the Bottom, Not the Top
Python's tracebacks say "Traceback (most recent call last)" right at the top. Most people read that phrase and start reading from the top. That phrase is telling you the opposite. The most recent call is at the bottom. That's where the error actually happened. The top is where your program started. History, not the crime scene.
Traceback (most recent call last): File "solution.py", line 14, in <module> result = merge_intervals(intervals) File "solution.py", line 8, in merge_intervals if current[1] >= intervals[i][0]: IndexError: list index out of range
The last line is the error type and message. Start there. IndexError: list index out of range tells you the category: you're accessing an array with a bad index. The frame directly above it is solution.py, line 8. That's the exact line. Everything above that is the call chain showing how execution got there. You rarely need it.
The fix for most bugs lives in the bottom two or three lines of the traceback. The frames above them are context, not action items.
JavaScript browser errors work the same way. The first line printed is the error, and the call stack beneath it goes from most recent (top) to least recent (bottom). Read the exception, then look at the first frame that mentions your file.
Java is slightly different. The most recent frame is at the top of the stack:
Exception in thread "main" java.lang.NullPointerException
at Solution.mergeLists(Solution.java:23)
at Solution.main(Solution.java:5)
Frame one is where it crashed. Frame two is who called it. Start at frame one.
The Error Type Is Your Cheat Code
Before you read the message text, read the error class name. It narrows the search space dramatically.

Every developer has done the ChatGPT paste. This post is here so you can stop doing that.
NullPointerException (Java), AttributeError (Python), TypeError: Cannot read properties of undefined (JavaScript) all mean the same thing: you tried to use something that doesn't exist. A variable is null, a dictionary key was never set, a function returned None and you chained a call off it. Look at the flagged line and find the thing being accessed. One of those references is null.
IndexError (Python), ArrayIndexOutOfBoundsException (Java): your index is out of range. Check your loop boundary. If you're iterating to len(array) instead of len(array) - 1, or your array is empty and you're accessing [0], that's your bug.
RecursionError: maximum recursion depth exceeded (Python), StackOverflowError (Java), RangeError: Maximum call stack size exceeded (JavaScript): infinite recursion. Your base case is missing or unreachable. If you see the same function name repeating in the trace, you found it.
TypeError (Python and JS), ClassCastException (Java): you're treating a value as a type it isn't. A string where a number is expected, a list where a dictionary is expected.
SyntaxError: the parser couldn't read your code at all. This one has a gotcha covered below.
Knowing the category cuts your debugging time in half because each category has a small, predictable set of causes. You're not searching the whole file. You're running a targeted check.
The Reported Line Is Not Always the Buggy Line
The error message shows you where the problem was detected, not where it was created. Those two locations are often nowhere near each other.
Take Python's SyntaxError. If you forget a closing parenthesis:
result = sum( x for x in range(10) print(result) # SyntaxError points here, line 4
Python's parser sees an unclosed ( and keeps reading, expecting the ). It gives up when it hits print on line 4 and throws SyntaxError: invalid syntax pointing at line 4. The actual mistake is line 1. When the flagged line looks completely fine, look one or two lines above it. The parser was confused long before it said anything.
The same gap shows up with NullPointerException. Java throws the exception at the line where you dereferenced null, but null usually got set somewhere earlier: a return value you didn't check, a variable you never initialized. The crash site and the bug site are different. Once you know the crash site from the stack trace, trace backward through the logic to find where null entered the picture.
Java 14 introduced better NPE messages via JEP 358. Before Java 14, you'd see:
NullPointerException
Nothing else. Extremely helpful. Since Java 14 (enabled by default in Java 21):
Cannot read field "next" because "node.left" is null
That tells you exactly which link in the chain was null. If you're on an older JVM during an interview, read the stack frame, find the line, and mentally identify every possible null in that expression.
Ignore 90% of That Stack Trace
Some of the worst-looking errors happen when a library throws internally. Fifty frames of framework code and you're wondering which line of your solution is responsible. Spoiler: it's still your solution.
Scan down from the top, looking for a frame that references your file. Not java.util.LinkedList, not collections.abc. Your file. Your class.
Exception in thread "main" java.lang.IllegalArgumentException: Duplicate key
at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
at java.util.HashMap.merge(HashMap.java:1291)
at java.util.stream.Collectors.lambda$toMap$1(Collectors.java:620)
at Solution.groupAnagrams(Solution.java:18) <-- here
at Solution.main(Solution.java:5)
Everything above Solution.java:18 is library code executing correctly. Your code at line 18 passed bad input to the library. The library is not wrong. You told it to do something it couldn't handle.
Java's Chain of Exceptions and the "... 23 More" Mystery
When Java wraps one exception inside another, you get chained output:
java.lang.RuntimeException: Failed to process input
at Solution.process(Solution.java:31)
at Solution.main(Solution.java:10)
Caused by: java.lang.NullPointerException: Cannot read field "value"
at Solution.parseNode(Solution.java:19)
... 1 more
Jump directly to the last Caused by: block. That's the root error. The outer exception is commentary about what the program was doing when the inner one blew up. Fix parseNode, and the outer RuntimeException disappears automatically.
The ... 1 more is not hiding information. Java prints it to avoid repeating frames already shown in the outer exception's stack trace. The N more is Java telling you how many shared frames it omitted. You can safely ignore it.
In an Interview: One Fix at a Time
Under pressure, the instinct is to spot three suspicious things and change all of them at once. Resist this.

Relatable in your bedroom. Career-limiting when someone is watching.
If you make three changes and the error goes away, you don't know which one fixed it and you can't explain your reasoning. The interviewer noticed. They watched you shotgun the code and got no signal about whether you understood what happened.
The correct loop:
- Read the error type. Categorize the bug.
- Find the frame in your code. Note the line number.
- Form a single hypothesis about what's wrong.
- Make one change.
- Re-run.
Narrate out loud. "I'm seeing an IndexError on line 8. I'm accessing intervals[i][0] and my loop goes from 0 to len(intervals). I think the condition should be i < len(intervals) - 1. Let me change that."
That's systematic thinking, not lucky guessing. An interviewer watching you silently change three things and re-run gets nothing to write about. Silence plus random edits reads as panic.
SpaceComplexity puts you in exactly these situations: live, time-pressured, with a real interviewer listening. Narrating while you read the error, forming one hypothesis at a time, is a practiced skill. The only way to build it is repetition under pressure.
For more on the communication side of debugging under pressure, the post on debugging in a coding interview covers the trace-table method and the one-fix-at-a-time rule in more detail.
The Short Version
- Read tracebacks bottom-up (Python) or top-of-trace first (Java/JS). Most recent frame is last in Python, first in Java.
- The error type tells you the category: null access, bounds error, infinite recursion, type mismatch, parse failure.
- The reported line is where the error was detected. The bug often lives one line earlier (SyntaxError) or several calls earlier (NullPointerException).
- In long stack traces, skip library frames. Find the first frame with your file.
- In Java, jump to the last
Caused by:. Ignore... N more. - Make one change. Re-run. Explain what you changed and why.