{"record":{"id":"112884aa21f4fb44","repo":"aeron-io/aeron","slug":"unexpected-image-close-during-catchup-position-position","errorCode":null,"errorMessage":"unexpected image close during catchup: position=<position>","messagePattern":"unexpected image close during catchup: position=<position>","errorType":"exception","errorClass":"ClusterEvent","httpStatus":null,"severity":"critical","filePath":"aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModuleAgent.java","lineNumber":1993,"sourceCode":"\n    int catchupPoll(final long limitPosition, final long nowNs)\n    {\n        int workCount = 0;\n\n        if (ConsensusModule.State.ACTIVE == state || ConsensusModule.State.SUSPENDED == state)\n        {\n            if (null == appendPosition)\n            {\n                throw new ClusterEvent(\n                    \"unexpected recording stop during catchup: position=\" + logAdapter.position());\n            }\n\n            final long currentAppendPosition = appendPosition.get();\n            final int fragments = logAdapter.poll(min(currentAppendPosition, limitPosition));\n            workCount += fragments;\n            if (0 == fragments && logAdapter.isImageClosed())\n            {\n                throw new ClusterEvent(\n                    \"unexpected image close during catchup: position=\" + logAdapter.position());\n            }\n\n            workCount += updateFollowerPosition(\n                election.leader().publication(),\n                nowNs,\n                leadershipTermId,\n                currentAppendPosition,\n                APPEND_POSITION_FLAG_CATCHUP);\n            commitPosition.proposeMaxRelease(logAdapter.position());\n        }\n\n        if (nowNs > (timeOfLastAppendPositionUpdateNs + leaderHeartbeatTimeoutNs) &&\n            ConsensusModule.State.ACTIVE == state)\n        {\n            throw new ClusterEvent(\n                \"no catchup progress:\" +\n                \" commitPosition=\" + commitPosition.getPlain() +","sourceCodeStart":1975,"sourceCodeEnd":2011,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModuleAgent.java#L1975-L2011","documentation":"During leader catchup, a follower polls the log image to replay missing entries. Aeron throws this ClusterEvent when the image carrying the recording is unexpectedly closed while catchup fragments are still expected, meaning the log stream ended before the follower reached the leader's position.","triggerScenarios":"Thrown in ConsensusModuleAgent while polling for catchup when logAdapter.poll() returns 0 fragments and logAdapter.isImageClosed() is true.","commonSituations":"Leader's recording publication closed or leader failed mid-catchup; network disconnect ending the image; archive/recording ended prematurely; a new election starting concurrently.","solutions":["Check the leader's health and logs around the failure time; the leader likely terminated its log publication","Verify network stability between follower and leader (timeouts, firewalls, TCP resets)","Confirm all nodes run compatible Aeron versions and consistent cluster/channel configuration","Restart the follower node so it rejoins and triggers a fresh election/catchup cycle"],"exampleFix":"// before: catchup poll with no guard against repeated failure\nlogAdapter.poll(limitPosition);\n\n// after: wrap agent failure so cluster restarts the node cleanly\ntry\n{\n    workCount += logAdapter.poll(limitPosition);\n}\ncatch (ClusterEvent e)\n{\n    ctx.errorLog().log(e);\n    consensusModuleAgent.close(); // allow re-election and rejoin\n}","handlingStrategy":"retry","validationCode":"// verify cluster connectivity before joining\nif (!InetAddress.getByName(clusterMemberHost).isReachable(2000))\n{\n    throw new IllegalStateException(\"cannot reach cluster member\");\n}","typeGuard":null,"tryCatchPattern":"catch (ClusterEvent e)\n{\n    log.error(\"catchup image closed, rejoining cluster\", e);\n    clusterContainer.close();\n    // re-launch container to trigger fresh election\n}","preventionTips":["Monitor leader health and member connectivity continuously","Keep all nodes on the same Aeron version","Ensure stable, low-loss network between cluster members"],"tags":["aeron","cluster","election","catchup","replication"],"backgroundTag":"unexpected-response-shape","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"}