{"record":{"id":"d7366165227a6319","repo":"aeron-io/aeron","slug":"unexpected-aeron-close-consensusmoduleagent","errorCode":null,"errorMessage":"unexpected Aeron close","messagePattern":"unexpected Aeron close","errorType":"exception","errorClass":"AgentTerminationException","httpStatus":null,"severity":"critical","filePath":"aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModuleAgent.java","lineNumber":535,"sourceCode":"        return clusterTimeUnit;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public IdleStrategy idleStrategy()\n    {\n        return this;\n    }\n\n    public void idle()\n    {\n        checkInterruptStatus();\n        aeronClientInvoker.invoke();\n        if (aeron.isClosed())\n        {\n            throw new AgentTerminationException(\"unexpected Aeron close\");\n        }\n\n        idleStrategy.idle();\n        pollArchiveEvents();\n    }\n\n    public void idle(final int workCount)\n    {\n        checkInterruptStatus();\n        aeronClientInvoker.invoke();\n        if (aeron.isClosed())\n        {\n            throw new AgentTerminationException(\"unexpected Aeron close\");\n        }\n\n        idleStrategy.idle(workCount);\n\n        if (0 == workCount)","sourceCodeStart":517,"sourceCodeEnd":553,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModuleAgent.java#L517-L553","documentation":"ConsensusModuleAgent.idle() is the agent duty-cycle idle hook. Before idling it checks whether the underlying Aeron client has been closed by an external actor; if so the agent cannot continue and throws AgentTerminationException so the consensus module shuts down cleanly instead of operating on a dead client.","triggerScenarios":"While the consensus module agent is idle (no work count), aeron.isClosed() returns true because someone called aeron.close() or a fatal error closed the client (e.g. driver death, uncuched client error, driver timeout).","commonSituations":"Media driver terminated or crashed while the consensus module kept running; another thread closed the shared Aeron client; driver heartbeat timeout due to a stalled or frozen system.","solutions":["Determine why the Aeron client closed: check the media driver logs for errors/timeout and keep the driver alive for the cluster's lifetime.","Ensure no application code closes the shared Aeron instance while the consensus module agent is running.","Shut down the consensus module as part of the same lifecycle as the Aeron client so close ordering is deliberate.","Check for driver timeout configuration (driverTimeoutMs) mismatch with slow GC/paging on the host."],"exampleFix":"// before\ndriver.close(); // closes media driver, Aeron client dies under the agent\n// after\nconsensusModule.close();\ndriver.close(); // close cluster components before the driver","handlingStrategy":"try-catch","validationCode":"// before starting the agent\nif (aeron.isClosed()) { throw new IllegalStateException(\"Aeron client closed before cluster agent start\"); }","typeGuard":null,"tryCatchPattern":"try { consensusModule.start(); } catch (AgentTerminationException e) { log.fatal(\"Aeron client closed: check media driver health\", e); shutdownCluster(); }","preventionTips":["Keep the media driver alive for the cluster's full lifetime.","Never close the shared Aeron client from other threads while the agent runs.","Tune driverTimeoutMs for realistic GC/paging pauses.","Shut down cluster components before the Aeron client."],"tags":["aeron","client-closed","agent","lifecycle"],"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"}