lysine-dev/retrofit · error · NullPointerException

scheduler == null

Error message

scheduler == null

What it means

RxJava2CallAdapterFactory.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 (create() for synchronous, createAsync() for asynchronous). It throws NullPointerException ('scheduler == null') behind a ConstantConditions suppression.

Solutions

  1. If you want no custom scheduler, use the dedicated factory: RxJava2CallAdapterFactory.create()() or RxJava2CallAdapterFactory.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 = RxJava2CallAdapterFactory.createWithScheduler(configScheduler);
// after
RxJava2CallAdapterFactory factory = configScheduler != null
    ? RxJava2CallAdapterFactory.createWithScheduler(configScheduler)
    : RxJava2CallAdapterFactory.createAsync();
Defensive patterns

Strategy: validation

Validate before calling

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

Try / catch

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

Prevention

When it happens

Trigger: Calling RxJava2CallAdapterFactory.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/698bb097bfa30aa1. Report an issue: GitHub.

Appendix: source

Thrown at retrofit-adapters/rxjava2/src/main/java/retrofit2/adapter/rxjava2/RxJava2CallAdapterFactory.java:81

   * Returns an instance which creates synchronous observables that do not operate on any scheduler
   * by default.
   */
  public static RxJava2CallAdapterFactory create() {
    return new RxJava2CallAdapterFactory(null, false);
  }

  /** Returns an instance which creates asynchronous observables. */
  public static RxJava2CallAdapterFactory createAsync() {
    return new RxJava2CallAdapterFactory(null, true);
  }

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

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

  private RxJava2CallAdapterFactory(@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)