{"record":{"id":"64ffa2695ffe6e29","repo":"grpc/grpc-java","slug":"the-transport-factory-is-closed-64ffa2","errorCode":null,"errorMessage":"The transport factory is closed.","messagePattern":"The transport factory is closed\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java","lineNumber":861,"sourceCode":"      this.enableKeepAlive = enableKeepAlive;\n      this.keepAliveTimeNanos = keepAliveTimeNanos;\n      this.keepAliveBackoff = new AtomicBackoff(\"keepalive time nanos\", keepAliveTimeNanos);\n      this.keepAliveTimeoutNanos = keepAliveTimeoutNanos;\n      this.flowControlWindow = flowControlWindow;\n      this.keepAliveWithoutCalls = keepAliveWithoutCalls;\n      this.maxInboundMetadataSize = maxInboundMetadataSize;\n      this.useGetForSafeMethods = useGetForSafeMethods;\n      this.channelCredentials = channelCredentials;\n\n      this.transportTracerFactory =\n          Preconditions.checkNotNull(transportTracerFactory, \"transportTracerFactory\");\n    }\n\n    @Override\n    public ConnectionClientTransport newClientTransport(\n        SocketAddress addr, ClientTransportOptions options, ChannelLogger channelLogger) {\n      if (closed) {\n        throw new IllegalStateException(\"The transport factory is closed.\");\n      }\n      final AtomicBackoff.State keepAliveTimeNanosState = keepAliveBackoff.getState();\n      Runnable tooManyPingsRunnable = new Runnable() {\n        @Override\n        public void run() {\n          keepAliveTimeNanosState.backoff();\n        }\n      };\n      InetSocketAddress inetSocketAddr = (InetSocketAddress) addr;\n      // TODO(carl-mastrangelo): Pass channelLogger in.\n      OkHttpClientTransport transport = new OkHttpClientTransport(\n          this,\n          inetSocketAddr,\n          options.getAuthority(),\n          options.getUserAgent(),\n          options.getEagAttributes(),\n          options.getHttpConnectProxiedSocketAddress(),\n          tooManyPingsRunnable,","sourceCodeStart":843,"sourceCodeEnd":879,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java#L843-L879","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nchannel.shutdownNow();\nManagedChannel c2 = channel; c2.getState(false); // new transport on closed factory\n// after\nchannel.shutdownNow();\nManagedChannel c2 = OkHttpChannelBuilder.forAddress(host, port).build();","handlingStrategy":"type-guard","validationCode":"if (channel.isShutdown() || channel.isTerminated()) { channel = rebuildChannel(); }","typeGuard":"ManagedChannel activeChannel(ManagedChannel ch, Supplier<ManagedChannel> rebuild) { return (ch.isShutdown() || ch.isTerminated()) ? rebuild.get() : ch; }","tryCatchPattern":"try { stub.call(req); } catch (IllegalStateException e) { if (e.getMessage().contains(\"transport factory is closed\")) { channel = rebuildChannel(); stub = newStub(channel); } else { throw e; } }","preventionTips":["Rebuild channels after shutdown instead of reusing them","Track channel lifecycle in a single owner class","Check isShutdown() before issuing calls"],"tags":["grpc","okhttp","shutdown","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}