ErrLookup › Background articles › NullPointerException ("x == null", "response == null", "scheduler == null"): Java null guards and accidental null dereferences explained

NullPointerException ("x == null", "response == null", "scheduler == null"): Java null guards and accidental null dereferences explained

NullPointerException is the Java Virtual Machine's signal that code touched a null reference — but across open-source libraries, most documented NPEs with messages like "scheduler == null" or "response == null" are deliberate fail-fast guards thrown the instant you pass a null argument to a factory, builder, or constructor. Developers meet this family when a dependency-injected value was never bound, a config property resolved to null, a test mock returned null, or a required resource (script engine, database, file) was missing at runtime. This article explains how the guard pattern varies across Retrofit, RxJava, RxAndroid, Zipkin, Dubbo, Seata, Flink, ANTLR, Canal, and others, and how to tell a deliberate guard from a real bug.

Distilled from 219 documented records across 36 repositories.

Background

The NullPointerException family has two distinct halves. The first half is the classic accidental dereference: the JVM itself throws when code calls a method or reads a field on a null reference, and the stack trace points at the offending line. The second half, which dominates the documented records in libraries such as Retrofit, RxAndroid, Zipkin, Dubbo, Seata, Flink, and ANTLR 4, is intentional: the library checks a mandatory argument at the top of a constructor or factory method and throws NullPointerException itself, usually via Objects.requireNonNull with a message naming the parameter. Messages like "error == null" (retrofit Result.error), "scheduler == null" (RxJavaCallAdapterFactory.createWithScheduler), "context == null" (JaxbConverterFactory.create), "category == null" (Zipkin ScribeCollector.Builder), "threadFactory" (Dubbo HashedWheelTimer), and "tokenSource cannot be null" (ANTLR BufferedTokenStream) all follow this pattern. The guard exists because the parameter has no sensible default, and failing at the call site is far easier to diagnose than a null propagating deep into library internals.

From the caller's side, a guard-style NPE arrives immediately at your own call line, with the stack trace anchored in your code — which is the point. The null itself almost never originates at that line. The records show it typically comes from an upstream source: a dependency-injection binding that was never configured (a Scheduler resolved from DI as null), a config property or environment variable that was misspelled or absent (Zipkin's Scribe category), a Mockito stub left unstubbed or explicitly returning null, a Kotlin nullable variable forwarded without a check, or a cache lookup that missed and returned null as a sentinel. Retrofit's Result factories illustrate the semantics: a Result must carry either a definite response or a definite error, so Result.response(null) and Result.error(null) are both rejected as semantically empty constructions.

The family also covers cases where NullPointerException is chosen for conditions that are not null dereferences at all, so behavior is library-specific. Canal throws NPE("Not implement yet") from an unimplemented dump(long, SinkFunction) method as a stub marker, and its MappingConfig.validate() uses NPE for missing YAML fields like dbMapping.database. JeecgBoot throws NPE("Specified file not found") for a missing download file where FileNotFoundException would be expected — a choice that can confuse generic catch blocks. APIJSON's "engine == null" reflects a missing javax.script engine, most often Nashorn's removal on JDK 15+. Reactive libraries add contract violations to the family: RxJava throws NPE("Operator ... returned a null Subscriber") when a custom FlowableOperator.apply() returns null, and RxAndroid throws when a scheduler Callable returns null — both because the Reactive-Streams spec forbids null participants. A few records (the SpringBoot-Labs demo endpoints) are intentionally thrown NPEs used to demonstrate global exception handling, not defects at all.

Common causes

What usually fixes it

Documented occurrences

…and 199 more across the corpus — use search.

Honest provenance: generated on 2026-08-14 from AI-assisted analysis of the linked records. See how records are made.