Reading a Stack Trace in Java

Naveen AnamaneniUpdated · 5 min read

A stack trace is the block of text Java prints when an exception isn't caught. Beginners often scroll past it, but it's the most useful debugging tool you have: it tells you what went wrong, where it happened, and how the program got there. Reading one takes about ten seconds once you know the three parts.

A Trace, Part by Part

Trace.java
public class Trace {
    static int average(int[] marks) {
        int sum = 0;
        for (int m : marks) sum += m;
        return sum / marks.length;
    }
 
    static void report(String name, int[] marks) {
        System.out.println(name + ": " + average(marks));
    }
 
    public static void main(String[] args) {
        report("Navika", new int[] {80, 90});
        report("Srihitha", new int[] {});
    }
}
Terminal output
Navika: 85
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at Trace.average(Trace.java:5)
    at Trace.report(Trace.java:9)
    at Trace.main(Trace.java:14)
What went wrong, where, and how the program got there

How to read it

  1. First line: what. The exception class and its message. "ArithmeticException: / by zero" already tells you an integer was divided by zero.
  2. Top at line: where. Trace.average(Trace.java:5) means the method average in class Trace, file Trace.java, line 5. That's the exact line that threw.
  3. Lines below: how you got there. Each at line is a method call that was still in progress, newest first. average was called from report at line 9, which was called from main at line 14 (Srihitha's report, with an empty array).

Your Code vs Library Code

When the exception starts inside the JDK or a library, the top lines belong to code you didn't write. Skip down to the first line from your own classes:

Marks.java
public class Marks {
    static int total = 0;
 
    static void read(String[] entries) {
        for (String e : entries) {
            String text = e.strip();
            System.out.println("reading " + text);
            total += Integer.parseInt(text);
        }
    }
 
    public static void main(String[] args) {
        String[] entries = {"80", "9O"};
        System.out.println("start");
        read(entries);
    }
}
Terminal output
Exception in thread "main" java.lang.NumberFormatException: For input string: "9O"
    at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
    at java.base/java.lang.Integer.parseInt(Integer.java:565)
    at java.base/java.lang.Integer.parseInt(Integer.java:662)
    at Marks.read(Marks.java:8)
    at Marks.main(Marks.java:15)

The java.base/java.lang... lines are inside the JDK. The JDK isn't broken; it's reporting bad input. The first line from your code, Marks.read(Marks.java:8), is where you passed "9O" (with a letter O) to parseInt. Fix it there.

Caused by

When one exception is wrapped in another (see "Chained Exceptions in Java"), the trace shows both, with the original under Caused by::

Terminal output
Exception in thread "main" Chain$ReportException: Bad marks for Advitha: 9O
    at Chain.parseMarks(Chain.java:10)
    at Chain.main(Chain.java:15)
Caused by: java.lang.NumberFormatException: For input string: "9O"
    at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
    at java.base/java.lang.Integer.parseInt(Integer.java:565)
    at java.base/java.lang.Integer.parseInt(Integer.java:662)
    at Chain.parseMarks(Chain.java:8)
    ... 1 more

The top part describes the problem in your program's terms; the Caused by part shows the original, low-level failure. ... 1 more means the remaining frames are the same as in the trace above, so they aren't repeated. When a trace has several Caused by sections, the last one is usually the root cause.

Common Mistakes

Reading only the last line. The top lines usually matter most.

Blaming the JDK. Library frames at the top usually mean you passed it something invalid; find your first frame.

Printing only e.getMessage() in a catch. You lose the trace; log the exception itself or call e.printStackTrace() while debugging.

Interview Corner

How do you read a Java stack trace?

The first line gives the exception type and message, which describe what went wrong. The following "at" lines list the method calls active at that moment, from the most recent at the top to the oldest at the bottom, each with its class, method, file and line number. The topmost frame in your own code is usually where to start fixing. "Caused by" sections show wrapped original exceptions, and the last cause is typically the root cause.

Practice

  1. Easy: Run Trace.java, then change main so the empty array is passed first. How does the trace change?
  2. Harder: Add a fourth method between report and main, run it again, and match each at line to a line of your code.

Quick check: Stack traces

4 questions
1What does the first line of a stack trace tell you?
2In which order are the at lines listed?
3The top lines are inside java.base. Where should you look?
4What does "Caused by" show?

Key Takeaways

Was this tutorial helpful?

Lesson 230 of 482