quarkusio/quarkus · error · IllegalArgumentException
ExecutorService must not be null
Error message
ExecutorService must not be null
What it means
Thrown by QuarkusRestClientBuilder.executorService when a null ExecutorService is passed. The builder wraps the executor with ContextualExecutors so async calls run with proper context propagation, and a null executor has no valid meaning.
Source
Thrown at extensions/resteasy-classic/resteasy-client/runtime/src/main/java/io/quarkus/restclient/runtime/QuarkusRestClientBuilder.java:246
}
@Override
public RestClientBuilder keyStore(KeyStore keyStore, String keystorePassword) {
this.keyStore = keyStore;
this.keystorePassword = keystorePassword;
return this;
}
@Override
public RestClientBuilder hostnameVerifier(HostnameVerifier hostnameVerifier) {
this.hostnameVerifier = hostnameVerifier;
return this;
}
@Override
public RestClientBuilder executorService(ExecutorService executor) {
if (executor == null) {
throw new IllegalArgumentException("ExecutorService must not be null");
}
executorService = ContextualExecutors.wrap(executor);
return this;
}
public <T> T build(Class<T> aClass, ClientHttpEngine httpEngine)
throws IllegalStateException, RestClientDefinitionException {
RestClientListeners.get().forEach(listener -> listener.onNewClient(aClass, this));
// Interface validity
verifyInterface(aClass);
if (baseURI == null) {
throw new IllegalStateException("Neither baseUri nor baseUrl was specified");
}
// Provider annotationsView on GitHub (pinned to e1c734241f)
Solutions
- Pass a non-null ExecutorService, e.g. a ManagedExecutor or Executors.newFixedThreadPool(...)
- Use Quarkus's ManagedExecutor injection (io.quarkus.threadpool.ThreadPoolConfig managed executor) instead of building one by hand
- Omit the executorService call entirely and let the builder use its default executor
Example fix
// before
ExecutorService exec = lookupExecutor(); // may return null
builder.executorService(exec); // IllegalArgumentException
// after
ExecutorService exec = lookupExecutor();
if (exec != null) {
builder.executorService(exec);
} Defensive patterns
Strategy: validation
Validate before calling
Objects.requireNonNull(executor, "ExecutorService must not be null");
Try / catch
try {
builder.executorService(exec);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("ExecutorService must not be null")) {
builder.executorService(Executors.newFixedThreadPool(4));
} else {
throw e;
}
} Prevention
- Use Quarkus ManagedExecutor injection to guarantee a non-null executor
- Skip the executorService call to use the builder default
- Null-check any lazily resolved executor before passing it
When it happens
Trigger: Calling builder.executorService(null); passing an executor field/lookup result that resolved to null (e.g. container-managed executor not available, failed JNDI/CDI lookup).
Common situations: Programmatic client building in tests where an executor mock wasn't wired; relying on a ManagedExecutorService that isn't injected; refactor leaving the executor uninitialized.
Related errors
- proxyHost must not be null
- Invalid port number
- Invalid parameter index '${index}' used when obtaining param
- Name cannot start with '/':${name}
- Predicate already set
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/b5b9fb51b23b5f67.
Report an issue: GitHub.