Helpful NullPointerException Messages

Naveen AnamaneniUpdated · 4 min read

For years, a NullPointerException came with no message at all, just a line number. On a line like student.address.city.length(), that left you guessing: was student null? address? city? Since Java 14, the JVM writes a helpful message that names the exact reference that was null and the action that failed. It's on by default, and it turns many debugging sessions into a ten-second fix.

Messages That Point at the Problem

Helpful.java
public class Helpful {
    static class Address { String city; }
    static class Student { Address address; }
 
    public static void main(String[] args) {
        Student s = new Student();
        s.address = new Address();
        try {
            System.out.println(s.address.city.length());
        } catch (NullPointerException e) {
            System.out.println(e.getMessage());
        }
 
        s.address = null;
        try {
            System.out.println(s.address.city);
        } catch (NullPointerException e) {
            System.out.println(e.getMessage());
        }
 
        int[] marks = null;
        try {
            System.out.println(marks[0]);
        } catch (NullPointerException e) {
            System.out.println(e.getMessage());
        }
 
        Integer bonus = null;
        try {
            int b = bonus;
        } catch (NullPointerException e) {
            System.out.println(e.getMessage());
        }
    }
}
Terminal
javac -g Helpful.java
java Helpful
Terminal output
Cannot invoke "String.length()" because "s.address.city" is null
Cannot read field "city" because "s.address" is null
Cannot load from int array because "marks" is null
Cannot invoke "java.lang.Integer.intValue()" because "bonus" is null

How it works

Each message has two parts:

  1. What Java tried to do: call length(), read the field city, load from an array, or unbox an Integer.
  2. Which reference was null: "s.address.city", "s.address", "marks", "bonus". In the first case, s and s.address were fine; only city was null. No guessing needed.

Getting Variable Names

The messages show local variable names only when the class was compiled with debug information for local variables. Without it, you'll see placeholders:

Compiled withFirst message
javac -g Helpful.java (IDEs and Maven/Gradle do this by default)because "s.address.city" is null
Plain javac Helpful.javabecause "<local1>.address.city" is null
A lambda's captured variable, no -gbecause "<parameter1>" is null

Fields like address and city are always named; only local variables and parameters need -g.

All the Actions It Describes

Message starts withThe null reference was used to...
Cannot invoke "X.m()"Call a method
Cannot read field "f"Read a field
Cannot assign field "f"Write a field
Cannot load from int arrayRead an array element
Cannot store to int arrayWrite an array element
Cannot read the array lengthUse .length
Cannot throw exceptionthrow null
Cannot enter synchronized blocksynchronized (null)

Common Mistakes

Ignoring the message and reading only the line number. The message usually names the culprit directly.

Catching NPEs instead of fixing them. The message tells you which reference needs a null check or initialization.

Being puzzled by <local1>. Compile with -g, or run from an IDE.

Practice

  1. Easy: Write a line that throws Cannot read the array length because "names" is null and fix it.
  2. Harder: Build a three-level chain order.customer.phone.trim() where only phone is null. Predict the message, then run it.

Quick check: Helpful NPE messages

4 questions
1Since which version are NPE messages helpful by default?
2What does "because "s.address" is null" tell you?
3Why might the message show ?
4What should you do with the information?

Key Takeaways

Was this tutorial helpful?

Lesson 235 of 482