lysine-dev/retrofit · error · NullPointerException

scheduler == null

Error message

scheduler == null

What it means

RxJava3CallAdapterFactory.createWithScheduler(Scheduler) builds an adapter factory that subscribeOn's the supplied scheduler by default. Passing null is rejected because the factory would then hold no scheduler to apply; for the no-scheduler case the library provides dedicated factory methods (createSynchronous() for synchronous, createAsync() for asynchronous). It throws NullPointerException ('scheduler == null') behind a ConstantConditions suppression.

Source

Thrown at retrofit-adapters/rxjava3/src/main/java/retrofit2/adapter/rxjava3/RxJava3CallAdapterFactory.java:86

    return new RxJava3CallAdapterFactory(null, true);
  }

  /**
   * Returns an instance which creates synchronous observables that do not operate on any scheduler
   * by default. Applying {@code subscribeOn(..)} will change the scheduler on which the HTTP calls
   * are made.
   */
  public static RxJava3CallAdapterFactory createSynchronous() {
    return new RxJava3CallAdapterFactory(null, false);
  }

  /**
   * Returns an instance which creates synchronous observables that {@code subscribeOn(..)} the
   * supplied {@code scheduler} by default.
   */
  @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
  public static RxJava3CallAdapterFactory createWithScheduler(Scheduler scheduler) {
    if (scheduler == null) throw new NullPointerException("scheduler == null");
    return new RxJava3CallAdapterFactory(scheduler, false);
  }

  private final @Nullable Scheduler scheduler;
  private final boolean isAsync;

  private RxJava3CallAdapterFactory(@Nullable Scheduler scheduler, boolean isAsync) {
    this.scheduler = scheduler;
    this.isAsync = isAsync;
  }

  @Override
  public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    Class<?> rawType = getRawType(returnType);

    if (rawType == Completable.class) {
      // Completable is not parameterized (which is what the rest of this method deals with) so it

View on GitHub (pinned to d0b112dad0)

Solutions

  1. If you want no custom scheduler, use the dedicated factory: RxJava3CallAdapterFactory.createSynchronous()() or RxJava3CallAdapterFactory.createAsync().
  2. Otherwise supply a real Scheduler such as Schedulers.io(), Schedulers.computation(), or AndroidSchedulers.mainThread().
  3. Resolve the null at its source (DI binding / config property) rather than passing it through.

Example fix

// before
RxJavaCallAdapterFactory factory = RxJava3CallAdapterFactory.createWithScheduler(configScheduler);
// after
RxJava3CallAdapterFactory factory = configScheduler != null
    ? RxJava3CallAdapterFactory.createWithScheduler(configScheduler)
    : RxJava3CallAdapterFactory.createAsync();
Defensive patterns

Strategy: validation

Validate before calling

Scheduler s = resolveScheduler(); // may be null when unconfigured
RxJava3CallAdapterFactory factory =
    s != null
      ? RxJava3CallAdapterFactory.createWithScheduler(s)
      : RxJava3CallAdapterFactory.createAsync();

Try / catch

try {
  factory = RxJava3CallAdapterFactory.createWithScheduler(s);
} catch (NullPointerException e) {
  // s was null; fall back to the async factory
  factory = RxJava3CallAdapterFactory.createAsync();
}

Prevention

When it happens

Trigger: Calling RxJava3CallAdapterFactory.createWithScheduler(null), most often when the scheduler is read from DI/configuration/env that was not bound and resolved to null. Thrown immediately at the top of createWithScheduler.

Common situations: Reading a Scheduler from a DI graph or config property that resolved to null; conditional scheduler selection that falls through to null; copy-paste of createWithScheduler without choosing the right base factory method; environment differences (e.g. Android main thread scheduler absent in unit tests).

Related errors


AI-assisted analysis of lysine-dev/retrofit@d0b112dad0 (2026-08-13). Data as JSON: /api/errors/af8148187767b3a8. Report an issue: GitHub.