{"record":{"id":"26f5fd4c9c7e80eb","repo":"aeron-io/aeron","slug":"aeron-client-is-closed","errorCode":null,"errorMessage":"Aeron client is closed","messagePattern":"Aeron client is closed","errorType":"exception","errorClass":"AeronException","httpStatus":null,"severity":"error","filePath":"aeron-client/src/main/java/io/aeron/ClientConductor.java","lineNumber":1715,"sourceCode":"            final long registrationId = driverProxy.rejectImage(correlationId, position, reason);\n            awaitResponse(registrationId);\n        }\n        finally\n        {\n            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    {","sourceCodeStart":1697,"sourceCodeEnd":1733,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-client/src/main/java/io/aeron/ClientConductor.java#L1697-L1733","documentation":"ClientConductor.ensureActive() is called at the start of every public client operation. When the conductor has been closed (isClosed) it throws AeronException(\"Aeron client is closed\") — after a client is closed all its resources (publications, subscriptions, counters) are released and no further commands are accepted. Calling into Aeron after Aeron.close() (or after the client driver has force-closed the conductor) produces this error.","triggerScenarios":"Using an Aeron instance, or any of its Publications/Subscriptions/Counters, after calling aeron.close(); submitting async commands (addCounter, addPublication) from another thread while shutdown is in progress; agent shutdown hooks or Spring/other lifecycle containers closing Aeron while application threads still publish.","commonSituations":"Graceful shutdown races: one thread closes Aeron while publisher threads continue sending; reusing a cached Aeron client after an application restart within the same JVM (e.g. hot redeploy); error-handling paths that close the client then attempt cleanup via the same client; tests closing a shared client in @AfterEach while async work continues.","solutions":["Coordinate shutdown: stop all producer/consumer threads and join them before calling aeron.close().","Guard client access with an application-level 'running' flag so no calls happen after close.","Check aeron.isClosed() (or hold the client behind a lifecycle manager) before submitting new commands.","Create a fresh Aeron instance if you genuinely need to reconnect after close — clients are not reusable.","Catch AeronException in background threads and treat it as a shutdown signal rather than an error."],"exampleFix":"// before\nexecutor.shutdown();\naeron.close();\n// publisher thread still running:\npublication.offer(buffer); // AeronException: Aeron client is closed\n\n// after\nrunning.set(false);\nexecutor.shutdown();\nexecutor.awaitTermination(5, TimeUnit.SECONDS); // let publishers drain\naeron.close();","handlingStrategy":"try-catch","validationCode":"if (aeron.isClosed()) {\n    return; // or recreate the client\n}","typeGuard":"boolean usable(Aeron aeron) {\n    return aeron != null && !aeron.isClosed();\n}","tryCatchPattern":"try {\n    publication.offer(buffer);\n} catch (AeronException e) {\n    if (e.getMessage().contains(\"client is closed\")) {\n        // expected during shutdown: stop the worker loop\n        return;\n    }\n    throw e;\n}","preventionTips":["Stop and join all producer/consumer threads before aeron.close()","Route all client access through a lifecycle manager with a running flag","Never reuse an Aeron instance after close; create a new one","Treat this exception in background threads as a shutdown signal","Avoid closing shared clients in test teardown while async work is in flight"],"tags":["aeron","client-lifecycle","shutdown-race","closed-resource"],"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-15T23:17:13.987Z"}