{"record":{"id":"280a1d517701df81","repo":"aeron-io/aeron","slug":"unexpected-aeron-close-clusterbackupagent","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/ClusterBackupAgent.java","lineNumber":635,"sourceCode":"        {\n            if (EventCode.ERROR == eventCode || EventCode.AUTHENTICATION_REJECTED == eventCode)\n            {\n                throw new ClusterException(eventCode + \": \" + detail);\n            }\n            else if (EventCode.REDIRECT == eventCode)\n            {\n                consensusPublicationGroup.closeAndExcludeCurrent();\n                state(RESET_BACKUP, epochClock.time());\n            }\n        }\n    }\n\n    private int slowTick(final long nowMs)\n    {\n        int workCount = aeronClientInvoker.invoke();\n        if (aeron.isClosed())\n        {\n            throw new AgentTerminationException(\"unexpected Aeron close\");\n        }\n\n        if (nowMs >= markFileUpdateDeadlineMs)\n        {\n            markFileUpdateDeadlineMs = nowMs + MARK_FILE_UPDATE_INTERVAL_MS;\n            markFile.updateActivityTimestamp(nowMs);\n        }\n\n        workCount += pollBackupArchiveEvents();\n\n        if (NULL_VALUE == correlationId && null != clusterArchive)\n        {\n            final String errorResponse = clusterArchive.pollForErrorResponse();\n            if (null != errorResponse)\n            {\n                ctx.countedErrorHandler().onError(new ClusterEvent(\"cluster archive error: \" + errorResponse));\n                state(RESET_BACKUP, nowMs);\n            }","sourceCodeStart":617,"sourceCodeEnd":653,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-cluster/src/main/java/io/aeron/cluster/ClusterBackupAgent.java#L617-L653","documentation":"The backup agent's slowTick invokes the Aeron client invoker and checks whether the shared Aeron client has been closed. An unexpected close of the underlying Aeron client means the agent cannot make progress, so AgentTerminationException is thrown to terminate the agent deliberately.","triggerScenarios":"Something external closes the Aeron client (or its conductor) while ClusterBackupAgent is running — e.g. another owner calls aeron.close(), an unrecoverable client error closes the conductor, or shutdown hooks close the client.","commonSituations":"Application code sharing one AeronClient across components closing it while a backup is still running; Aeron client terminating itself after a fatal driver error.","solutions":["Ensure no other component closes the shared Aeron client while cluster backup is running; tie ownership/lifecycle to the backup.","Inspect the driver/error logs for the root cause that closed the client (e.g. driver inactive) and fix that first.","Restart the backup process once the Aeron driver is healthy."],"exampleFix":"// before\nsharedAeron.close(); // elsewhere in the app while backup runs\n// after\n// close only after ClusterBackup is stopped: backup.close(); then sharedAeron.close();","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"AgentRunner runner = AgentRunner.run(...); // catch AgentTerminationException in runner error handler\n(new AgentRunner(..., (code, ex) -> { if (ex instanceof AgentTerminationException) { restartBackup(); } }))","preventionTips":["Never close the shared Aeron client while backup agents run","Monitor Aeron driver health to avoid client self-termination"],"tags":["aeron","lifecycle","agent"],"backgroundTag":"internal-invariant-violation","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"}