Salesforce Dictionary - Free Salesforce GlossarySalesforce Dictionary
All errors
Apex

System.NullPointerException: Attempt to de-reference a null object

You tried to read a field, call a method, or index into something that turned out to be null. Apex doesn't have safe-navigation by default, so any `obj.field` blows up the moment `obj` is null.

Also seen asAttempt to de-reference a null object·System.NullPointerException·FATAL_ERROR System.NullPointerException

The Apex runtime says you de-referenced null. That phrasing trips up newcomers — "de-reference" just means "look something up on this thing." Translation: you wrote x.y or x.method() or x[0], and x was null at runtime.

The five usual suspects

  1. A SOQL result you assumed had a row. [SELECT Id FROM Account WHERE Name = 'Foo' LIMIT 1] returns an empty list, but you wrote Account a = [SELECT ... LIMIT 1] and got a QueryException instead. Then you "fixed" it by changing to [SELECT ...][0] — and now you get a NullPointerException on the empty list. Or you queried a parent: Contact c.Account.Name is null whenever the contact has no AccountId.

  2. A trigger context map you forgot to populate. Trigger.oldMap is null in before insert and after insert. Reading from it during inserts throws.

  3. A field you forgot to query. Apex returns null for any field not in the SELECT clause — even if it has a value in the database. Chasing a chain like opp.Account.Owner.Email requires every link in the chain to be in the SELECT.

  4. A static variable that was never initialised. private static Map<Id, Account> CACHE; is null, not an empty map, until somebody assigns it.

  5. Apex 8.0+ safe navigation that the rest of the codebase isn't using. account?.Name returns null instead of throwing — but if the next operation expects a string, you've just moved the bug downstream.

How to nail down which one

Apex stack traces include the line number. Open the class at that line and read the left side of the dot. The thing immediately before the . is what's null. Then ask: where was that supposed to be assigned?

If it's a SOQL-derived value, log the query result size right before you use it:

List<Account> hits = [SELECT Id, Name FROM Account WHERE Name = :term];
System.debug('hits: ' + hits.size());
if (hits.isEmpty()) return;        // or throw a domain-specific error
Account a = hits[0];

If it's a relationship field, query the parent fields explicitly:

// Wrong: opp.Account is null because we never asked for it.
Opportunity opp = [SELECT Id, Name FROM Opportunity WHERE Id = :oppId];
String accName = opp.Account.Name;  // boom

// Right.
Opportunity opp = [SELECT Id, Name, Account.Name FROM Opportunity WHERE Id = :oppId];
String accName = opp.Account?.Name ?? 'Unknown';

The defensive pattern

For anything coming from outside your method, default to a guard at the top:

public static Decimal totalAmount(List<OpportunityLineItem> items) {
    if (items == null || items.isEmpty()) return 0;
    Decimal sum = 0;
    for (OpportunityLineItem oli : items) {
        if (oli.TotalPrice != null) sum += oli.TotalPrice;
    }
    return sum;
}

The cost of a one-line guard is negligible. The cost of a NullPointerException in production, on a daily scheduled job, at 3 AM, is a phone call.

Related dictionary terms