{"record":{"id":"ec982dfefed27d13","repo":"grpc/grpc-java","slug":"the-transport-factory-is-closed","errorCode":null,"errorMessage":"The transport factory is closed.","messagePattern":"The transport factory is closed\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"binder/src/main/java/io/grpc/binder/internal/BinderClientTransportFactory.java","lineNumber":87,"sourceCode":"    scheduledExecutorPool = checkNotNull(builder.scheduledExecutorPool);\n    offloadExecutorPool = checkNotNull(builder.offloadExecutorPool);\n    securityPolicy = checkNotNull(builder.securityPolicy);\n    bindServiceFlags = checkNotNull(builder.bindServiceFlags);\n    inboundParcelablePolicy = checkNotNull(builder.inboundParcelablePolicy);\n    binderDecorator = checkNotNull(builder.binderDecorator);\n    readyTimeoutMillis = builder.readyTimeoutMillis;\n    preAuthorizeServers = builder.preAuthorizeServers;\n    useLegacyAuthStrategy = builder.useLegacyAuthStrategy;\n\n    executorService = scheduledExecutorPool.getObject();\n    offloadExecutor = offloadExecutorPool.getObject();\n  }\n\n  @Override\n  public BinderClientTransport newClientTransport(\n      SocketAddress addr, ClientTransportOptions options, ChannelLogger channelLogger) {\n    if (closed) {\n      throw new IllegalStateException(\"The transport factory is closed.\");\n    }\n    return new BinderClientTransport(this, (AndroidComponentAddress) addr, options);\n  }\n\n  @Override\n  public ScheduledExecutorService getScheduledExecutorService() {\n    return executorService;\n  }\n\n  @Override\n  public SwapChannelCredentialsResult swapChannelCredentials(ChannelCredentials channelCreds) {\n    return null;\n  }\n\n  @Override\n  public void close() {\n    if (closed) {\n      return;","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/binder/src/main/java/io/grpc/binder/internal/BinderClientTransportFactory.java#L69-L105","documentation":"BinderClientTransportFactory.newClientTransport() checks its closed flag and throws IllegalStateException('The transport factory is closed.') when a new transport is requested after the factory has been shut down. The factory is closed when the owning channelbuilder/channel is disposed, so any late transport creation indicates the channel is being used after (or during) shutdown.","triggerScenarios":"Calling newClientTransport(...) on a BinderClientTransportFactory after close(); typically triggered when the channel attempts reconnect/transport creation after the channel (and its factory) has been closed.","commonSituations":"Using a ManagedChannel after shutdown(); concurrent shutdown while a call is still being placed; keeping a reference to a closed channel in a long-lived component (e.g. an Android Service recreated/rebound).","solutions":["Do not start new RPCs after calling shutdown()/shutdownNow() on the channel that owns the factory","Await channel termination (awaitTermination) and recreate a fresh channel if further calls are needed","Guard application code so lifecycle events (Android onDestroy/rebind) close the channel only when no calls will follow"],"exampleFix":"// before\nchannel.shutdown();\nstub.call(request); // may hit closed factory\n// after\nchannel.shutdown();\nchannel.awaitTermination(5, TimeUnit.SECONDS);\nchannel = BinderChannelBuilder.forAddress(addr, context).build();\nstub.call(request);","handlingStrategy":"try-catch","validationCode":"if (channel.isShutdown() || channel.isTerminated()) {\n  channel = BinderChannelBuilder.forAddress(addr, context).build();\n}\nstub.call(request);","typeGuard":"static boolean isUsable(ManagedChannel ch) {\n  return ch != null && !ch.isShutdown() && !ch.isTerminated();\n}","tryCatchPattern":"try {\n  stub.call(request);\n} catch (IllegalStateException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"transport factory is closed\")) {\n    channel = BinderChannelBuilder.forAddress(addr, context).build();\n    stub = newStub(channel);\n  } else { throw e; }\n}","preventionTips":["Never issue RPCs after channel shutdown(); recreate the channel if needed","Tie channel close() to Android component lifecycle with no in-flight calls","Use awaitTermination before reusing or discarding channel references","Keep a single channel owner per process to avoid racing shutdowns"],"tags":["grpc","binder","android","lifecycle","shutdown"],"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"}