grpc/grpc-java · error · IllegalStateException
The transport factory is closed.
Error message
The transport factory is closed.
What it means
OkHttpTransportFactory.newClientTransport throws IllegalStateException when the factory was already closed via close(). The factory is owned by the channel; using it after shutdown is a lifecycle violation.
Source
Thrown at okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java:861
this.enableKeepAlive = enableKeepAlive;
this.keepAliveTimeNanos = keepAliveTimeNanos;
this.keepAliveBackoff = new AtomicBackoff("keepalive time nanos", keepAliveTimeNanos);
this.keepAliveTimeoutNanos = keepAliveTimeoutNanos;
this.flowControlWindow = flowControlWindow;
this.keepAliveWithoutCalls = keepAliveWithoutCalls;
this.maxInboundMetadataSize = maxInboundMetadataSize;
this.useGetForSafeMethods = useGetForSafeMethods;
this.channelCredentials = channelCredentials;
this.transportTracerFactory =
Preconditions.checkNotNull(transportTracerFactory, "transportTracerFactory");
}
@Override
public ConnectionClientTransport newClientTransport(
SocketAddress addr, ClientTransportOptions options, ChannelLogger channelLogger) {
if (closed) {
throw new IllegalStateException("The transport factory is closed.");
}
final AtomicBackoff.State keepAliveTimeNanosState = keepAliveBackoff.getState();
Runnable tooManyPingsRunnable = new Runnable() {
@Override
public void run() {
keepAliveTimeNanosState.backoff();
}
};
InetSocketAddress inetSocketAddr = (InetSocketAddress) addr;
// TODO(carl-mastrangelo): Pass channelLogger in.
OkHttpClientTransport transport = new OkHttpClientTransport(
this,
inetSocketAddr,
options.getAuthority(),
options.getUserAgent(),
options.getEagAttributes(),
options.getHttpConnectProxiedSocketAddress(),
tooManyPingsRunnable,View on GitHub (pinned to 64daddc1f3)
Solutions
- Create a new channel (builder.build()) after shutdown instead of reusing the old one
- Guard application code with a check on channel.isShutdown()/isTerminated before issuing calls
- Do not close the transport factory while connections are still needed; manage the factory lifecycle with the channel
- Serialize shutdown logic so no requests are started concurrently with shutdown
Example fix
// before channel.shutdownNow(); ManagedChannel c2 = channel; c2.getState(false); // new transport on closed factory // after channel.shutdownNow(); ManagedChannel c2 = OkHttpChannelBuilder.forAddress(host, port).build();
Defensive patterns
Strategy: type-guard
Validate before calling
if (channel.isShutdown() || channel.isTerminated()) { channel = rebuildChannel(); } Type guard
ManagedChannel activeChannel(ManagedChannel ch, Supplier<ManagedChannel> rebuild) { return (ch.isShutdown() || ch.isTerminated()) ? rebuild.get() : ch; } Try / catch
try { stub.call(req); } catch (IllegalStateException e) { if (e.getMessage().contains("transport factory is closed")) { channel = rebuildChannel(); stub = newStub(channel); } else { throw e; } } Prevention
- Rebuild channels after shutdown instead of reusing them
- Track channel lifecycle in a single owner class
- Check isShutdown() before issuing calls
When it happens
Trigger: Calling newClientTransport after the channel/factory was shut down — e.g. creating RPCs on a channel after shutdownNow(), or reusing a shared OkHttpChannelBuilder transport factory across channel lifecycles.
Common situations: Application tries to make calls after channel.shutdown(); keeping a stale channel reference in a singleton after restart logic; race between shutdown and in-flight request creation.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- The transport factory is closed.
- Unable to load OkHttpChannelProvider
- Restricted: shutdown() is not allowed
- Restricted: shutdownNow() is not allowed
- The transport factory is closed.
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/64ffa2695ffe6e29.
Report an issue: GitHub.