💥 Exceptions & Errors · Intermediate

Reading a stack trace in Java

Finding the origin line and the Caused by section.

🧩 The mystery40 lines of red text just exploded in your console. Most beginners scroll straight to the bottom. The answer is usually near the top. Here's how to read it.

Anatomy of the red wall

The first line names the exception type and message. Then come **at lines: the call stack, most recent call first. The first at line is where the exception was thrown**; each line below is the caller that got you there.

Exception in thread "main"
  java.lang.IllegalStateException: no user
    at Service.find(Service.java:42)
    at Controller.show(Controller.java:17)
    at App.main(App.java:5)
🤔 Think first

Where did it break?

Which line points to the code that actually threw? at Cart.total(Cart.java:31) at Checkout.pay(Checkout.java:12) at Main.main(Main.java:8)

Think about it, then reveal the answer

**Cart.total, line 31** — the top frame, where the null was used. Checkout.pay and main are just the callers that led there.

Caused by chains

Wrapped exceptions add **Caused by: sections. The last one is usually the root cause — the original failure. ... 2 more** means the remaining frames are identical to the trace above, so Java prints them once and abbreviates the repeats.

AppException: startup failed
    at App.init(App.java:20)
Caused by: ConfigException: bad port
    at Config.load(Config.java:44)
    ... 2 more
Caused by: NumberFormatException: "80a"
    at Config.parsePort(Config.java:61)
    ... 3 more
🔮 Predict it

Frames in code

getStackTrace() returns the same frames as an array. What prints?

void a() { throw new RuntimeException(); }
void b() { a(); }
void main() {
    try { b(); }
    catch (RuntimeException e) {
        var st = e.getStackTrace();
        System.out.println(st[0].getMethodName()
            + " " + st[1].getMethodName());
    }
}
  1. a b
  2. b a
  3. main b
Show the answer

getStackTrace()[0] is the throw site (a), and each following frame is its caller (b, then main) — exactly the order of the at lines.

⚠️ The trap

Reading from the wrong end

Starting at the bottom (main) or at the outermost wrapper (AppException) wastes time. Find the **deepest Caused by:, then its top frame. If that frame is inside a library, scan down to the first line from your own code**.

💼 In the real world

Debugging production

Error trackers like Sentry group crashes by their top frames, and on-call engineers triage from the first at line of the root cause. Being fast at this is one of the most practical skills you can have — interviewers love handing candidates a stack trace.

Key takeaways

  1. First line: exception type + message
  2. First 'at' line = where it was thrown
  3. Lower 'at' lines = the callers
  4. Last 'Caused by:' = usually the root cause; '... N more' = frames shared with above
🤯 Did you know?

A stack trace is captured when the exception is *created*, not when it's thrown. Build new Exception() in one method and throw it in another, and the trace points at the creation line.

Practice questions

Where should you start looking for the root cause?

AppException: startup failed
    at App.init(App.java:20)
    at App.main(App.java:5)
Caused by: ConfigException: bad port
    at Config.load(Config.java:44)
    ... 2 more
Caused by: NumberFormatException: "80a"
    at Config.parsePort(Config.java:61)
    ... 3 more
  1. NumberFormatException at Config.parsePort, line 61
  2. AppException at App.init, line 20
  3. ConfigException at Config.load, line 44
  4. App.main, line 5
Check your answer

NumberFormatException at Config.parsePort, line 61. Each wrapper adds context, but the innermost 'Caused by' is the original failure: the port text "80a" couldn't be parsed.

What does `... 3 more` at the end of a 'Caused by' section mean?

  1. The remaining 3 frames are the same as in the trace above, so they're omitted
  2. 3 more exceptions were suppressed
  3. The program retried the call 3 more times
  4. 3 frames were lost because of an error
Check your answer

The remaining 3 frames are the same as in the trace above, so they're omitted. The cause's call stack ends with the same frames as the enclosing trace; Java prints them once and abbreviates the repeats.

Next: the "usual suspects" — eight runtime exceptions behind most Java bugs, and what each name is telling you.