quarkusio/quarkus · error · UnsupportedOperationException
shutdown not allowed on managed executor service
Error message
shutdown not allowed on managed executor service
What it means
DelegatingExecutorService wraps a Quarkus-managed executor (backed by virtual threads or the container-managed thread pool). Because the lifecycle of the underlying executor is owned by Quarkus, callers must not shut it down; shutdown() therefore throws UnsupportedOperationException unconditionally.
Source
Thrown at extensions/virtual-threads/runtime/src/main/java/io/quarkus/virtual/threads/DelegatingExecutorService.java:39
return delegate;
}
public boolean isShutdown() {
// container managed executors are never shut down from the application's perspective
return false;
}
public boolean isTerminated() {
// container managed executors are never shut down from the application's perspective
return false;
}
public boolean awaitTermination(final long timeout, final TimeUnit unit) {
return false;
}
public void shutdown() {
throw new UnsupportedOperationException("shutdown not allowed on managed executor service");
}
public List<Runnable> shutdownNow() {
throw new UnsupportedOperationException("shutdownNow not allowed on managed executor service");
}
public String toString() {
return delegate.toString();
}
}
View on GitHub (pinned to e1c734241f)
Solutions
- Remove the shutdown()/shutdownNow() call — Quarkus shuts the executor down itself
- Inject/accept a dedicated application-owned ExecutorService (e.g. Executors.newVirtualThreadPerTaskExecutor()) where lifecycle shutdown is required
- Wrap the managed executor so consuming third-party code never sees lifecycle methods
Example fix
// before
@PreDestroy
void stop() { executor.shutdown(); } // UnsupportedOperationException
// after
@PreDestroy
void stop() { /* managed by Quarkus; nothing to do */ } Defensive patterns
Strategy: validation
Validate before calling
if (executor instanceof DelegatingExecutorService || isQuarkusManaged(executor)) { /* skip shutdown */ } Type guard
boolean isManagedExecutor(ExecutorService es) { return es.getClass().getName().startsWith("io.quarkus.virtual.threads"); } Try / catch
try { executor.shutdown(); } catch (UnsupportedOperationException ignored) { /* managed by Quarkus */ } Prevention
- Never call shutdown/shutdownNow on injected Quarkus executors
- Do not pass managed executors to libraries that close their ExecutorService
- Provide a dedicated executor to third-party code that requires lifecycle control
When it happens
Trigger: Invoking shutdown() on the ExecutorService returned by Quarkus' managed executor injection or the virtual-threads support (e.g. from an @ApplicationScoped bean holding the executor and attempting cleanup in @PreDestroy/stop logic).
Common situations: Application shutdown hooks or library code (e.g. closing a client that accepts an ExecutorService) that calls executor.shutdown() out of habit on an injected managed executor.
Related errors
- shutdownNow not allowed on managed executor service
- Trying to invoke ContextPropagation on a partially-configure
- This executor is managed by the container and cannot be shut
- Can only sync state on the server side of remote dev mode
- All parameters have already been loaded, it is too late to c
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/3fa5260dadecd2c5.
Report an issue: GitHub.