openzipkin/zipkin · error · NullPointerException

executor == null

Error message

executor == null

What it means

MySQLStorage.Builder.executor throws NullPointerException when the java.util.concurrent.Executor argument is null. The executor runs the blocking JDBC work created by DataSourceCall, so async calls (enqueue) would have nowhere to run. The builder fails fast rather than defaulting silently.

Source

Thrown at zipkin-storage/mysql-v1/src/main/java/zipkin2/storage/mysql/v1/MySQLStorage.java:76

    public Builder datasource(DataSource datasource) {
      if (datasource == null) throw new NullPointerException("datasource == null");
      this.datasource = datasource;
      return this;
    }

    public Builder settings(Settings settings) {
      if (settings == null) throw new NullPointerException("settings == null");
      this.settings = settings;
      return this;
    }

    public Builder listenerProvider(@Nullable ExecuteListenerProvider listenerProvider) {
      this.listenerProvider = listenerProvider;
      return this;
    }

    public Builder executor(Executor executor) {
      if (executor == null) throw new NullPointerException("executor == null");
      this.executor = executor;
      return this;
    }

    @Override public MySQLStorage build() {
      return new MySQLStorage(this);
    }

    Builder() {
    }
  }

  static {
    System.setProperty("org.jooq.no-logo", "true");
  }

  final DataSource datasource;
  final DataSourceCall.Factory dataSourceCallFactory;

View on GitHub (pinned to 878ce2a1fa)

Solutions

  1. Pass an explicit executor, e.g. Executors.newSingleThreadExecutor() or a shared application executor such as ForkJoinPool.commonPool().
  2. Guard at the call site: builder.executor(executor != null ? executor : Runnable::run) for a same-thread fallback.
  3. If building via zipkin-server Spring configuration, let it build the storage so the executor wiring is handled for you.

Example fix

// before
builder.executor(null);

// after
builder.executor(Executors.newSingleThreadExecutor(daemonThreadFactory));
Defensive patterns

Strategy: validation

Validate before calling

builder.executor(executor != null ? executor : Executors.newSingleThreadExecutor());

Prevention

When it happens

Trigger: Calling builder.executor(null), or forwarding an executor field that was never initialized because async query execution was assumed to be optional.

Common situations: Assuming the builder creates a default executor; wiring an executor bean conditionally in Spring so it is absent in some profiles; refactoring that drops the executor() call but keeps a null variable being passed.

Related errors


AI-assisted analysis of openzipkin/zipkin@878ce2a1fa (2026-08-14). Data as JSON: /api/errors/c15c4dd46c4a6c49. Report an issue: GitHub.