{"record":{"id":"a21686a9e1fa1a8f","repo":"aeron-io/aeron","slug":"aeron-client-is-terminating","errorCode":null,"errorMessage":"Aeron client is terminating","messagePattern":"Aeron client is terminating","errorType":"exception","errorClass":"AeronException","httpStatus":null,"severity":"error","filePath":"aeron-client/src/main/java/io/aeron/ClientConductor.java","lineNumber":1720,"sourceCode":"            clientLock.unlock();\n        }\n    }\n\n    void onNextAvailableSessionId(final int nextSessionId)\n    {\n        lastResponseValue = nextSessionId;\n    }\n\n    private void ensureActive()\n    {\n        if (isClosed)\n        {\n            throw new AeronException(\"Aeron client is closed\");\n        }\n\n        if (isTerminating)\n        {\n            throw new AeronException(\"Aeron client is terminating\");\n        }\n    }\n\n    private void ensureNotReentrant()\n    {\n        if (isInCallback)\n        {\n            throw new AeronException(\"reentrant calls not permitted during callbacks\");\n        }\n    }\n\n    private LogBuffers logBuffers(final long registrationId, final String logFileName, final String channel)\n    {\n        LogBuffers logBuffers = logBuffersByIdMap.get(registrationId);\n        if (null == logBuffers)\n        {\n            try\n            {","sourceCodeStart":1702,"sourceCodeEnd":1738,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-client/src/main/java/io/aeron/ClientConductor.java#L1702-L1738","documentation":"ClientConductor.assertOpenAndNotTerminating() throws this when any public Aeron client API is called after the conductor has begun terminating (either close() was called or an internal error triggered termination). Once isTerminating is set the client is shutting down and no further API calls are permitted. It guards resource management against use-after-close.","triggerScenarios":"Calling any Aeron client API (addPublication, addSubscription, nextCorrelationId, etc.) after Aeron.close(), after the conductor self-terminated due to a driver timeout, or from a shutdown hook racing close().","commonSituations":"Publishers/subscriptions used from daemon threads that outlive the Aeron client; shutdown ordering issues where the JVM closes Aeron while worker threads still send; calling close() twice with a subsequent operation.","solutions":["Ensure close() is the last operation: shut down all threads that use Aeron before closing","Keep a single owner/lifecycle for the Aeron client and check isClosed() before API calls","If triggered by an internal timeout termination, investigate the earlier root-cause exception (driver timeout)","Restart the client: create a new Aeron instance instead of reusing the closed one"],"exampleFix":"// before\nexecutor.shutdown();\naeron.close();\nexecutor.awaitTermination(5, TimeUnit.SECONDS); // workers still using aeron after close\n// after\nexecutor.shutdown();\nexecutor.awaitTermination(5, TimeUnit.SECONDS);\naeron.close();","handlingStrategy":"try-catch","validationCode":"if (aeron.isClosed()) { throw new IllegalStateException(\"Aeron client already closed\"); }","typeGuard":"boolean usable(Aeron a) { return a != null && !a.isClosed(); }","tryCatchPattern":"try { publication.offer(buffer); } catch (AeronException e) { if (e.getMessage().contains(\"terminating\")) { reconnectClient(); } else { throw e; } }","preventionTips":["Shut down all producer/consumer threads before Aeron.close()","Use a single lifecycle owner for the client","Check isClosed() before API calls in mixed-thread code"],"tags":["lifecycle","aeron","use-after-close"],"backgroundTag":"invalid-state-transition","analyzedSha":"6d60124e15e35c11b49ba2e3c2c2858a09a18803","analyzedAt":"2026-09-12T11:17:07.683Z","contentChangedAt":"2026-09-12T11:17:07.683Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}