grpc/grpc-java · error · UnsupportedOperationException
Restricted: shutdownNow() is not allowed
Error message
Restricted: shutdownNow() is not allowed
What it means
Same restricted ExecutorService wrapper as the shutdown() case: shutdownNow() is disabled because the channel owns the executor's lifecycle. Calling it throws UnsupportedOperationException to protect channel invariants.
Source
Thrown at core/src/main/java/io/grpc/internal/ManagedChannelImpl.java:2194
@Override
public boolean isShutdown() {
return delegate.isShutdown();
}
@Override
public boolean isTerminated() {
return delegate.isTerminated();
}
@Override
public void shutdown() {
throw new UnsupportedOperationException("Restricted: shutdown() is not allowed");
}
@Override
public List<Runnable> shutdownNow() {
throw new UnsupportedOperationException("Restricted: shutdownNow() is not allowed");
}
@Override
public <T> Future<T> submit(Callable<T> task) {
return delegate.submit(task);
}
@Override
public Future<?> submit(Runnable task) {
return delegate.submit(task);
}
@Override
public <T> Future<T> submit(Runnable task, T result) {
return delegate.submit(task, result);
}
@OverrideView on GitHub (pinned to 64daddc1f3)
Solutions
- Use channel.shutdownNow() to cancel in-flight work; the channel will manage its executor.
- Shut down only the executor instance you originally supplied to the builder.
- Exclude the channel-wrapped executor from generic executor cleanup loops.
Example fix
// before List<Runnable> pending = executorService.shutdownNow(); // after channel.shutdownNow();
Defensive patterns
Strategy: try-catch
Validate before calling
boolean ownsExecutor = createdHere; // track ownership explicitly; never shutdownNow() executors received from gRPC
Try / catch
try {
executor.shutdownNow();
} catch (UnsupportedOperationException e) {
channel.shutdownNow();
} Prevention
- Never include channel-internal executors in generic cleanup loops.
- Call channel.shutdownNow() to force-cancel work.
- Keep ownership of executor lifecycle with ManagedChannelImpl.
When it happens
Trigger: Calling shutdownNow() on the ExecutorService view handed out by ManagedChannelImpl to internal components (balancers, listeners) during custom cleanup or cancellation paths.
Common situations: Custom LoadBalancer teardown code force-stopping all executors it references; generic shutdown hooks iterating over all ExecutorServices in an application.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Restricted: shutdown() is not allowed
- Can't set TLS settings for ALTS
- Unsupported operation getPort()
- Not implemented
- Not implemented
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/77dd342e1dddb007.
Report an issue: GitHub.