{"record":{"id":"7d1220f34fecd1d2","repo":"aeron-io/aeron","slug":"extension-subscription-joinposition-joinposition-does-not","errorCode":null,"errorMessage":"Extension subscription joinPosition (<joinPosition>) does not match logPosition (<logPosition>)","messagePattern":"Extension subscription joinPosition \\(<joinPosition>\\) does not match logPosition \\(<logPosition>\\)","errorType":"exception","errorClass":"ClusterException","httpStatus":null,"severity":"critical","filePath":"aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModuleAgent.java","lineNumber":1732,"sourceCode":"        connectLeaderLogSubscriptionForExtension(logPosition);\n    }\n\n    private void connectLeaderLogSubscriptionForExtension(final long logPosition)\n    {\n        if (null != consensusModuleExtension)\n        {\n            final Subscription subscription = aeron.addSubscription(localLogChannel, ctx.logStreamId());\n\n            idleStrategy.reset();\n            while (0 == subscription.imageCount())\n            {\n                idle();\n            }\n\n            final long joinPosition = subscription.imageAtIndex(0).joinPosition();\n            if (joinPosition != logPosition)\n            {\n                throw new ClusterException(\n                    \"Extension subscription \" +\n                    \"joinPosition (\" + joinPosition + \") does not match logPosition (\" + logPosition + \")\");\n            }\n\n            this.extensionLeaderSubscription = subscription;\n        }\n    }\n\n    void liveLogDestination(final String liveLogDestination)\n    {\n        this.liveLogDestination = liveLogDestination;\n    }\n\n    String liveLogDestination()\n    {\n        return liveLogDestination;\n    }\n","sourceCodeStart":1714,"sourceCodeEnd":1750,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModuleAgent.java#L1714-L1750","documentation":"When a follower becomes leader it attaches an extension subscription to receive the remainder of the log from the previous leader. The image's joinPosition must equal the node's current logPosition; if not, the log continuation would leave a gap or overlap, so the agent throws rather than corrupting the log.","triggerScenarios":"During leader election/extension, subscription.imageAtIndex(0).joinPosition() differs from the local logPosition — the incoming image starts at a different position than where this node's replay ended.","commonSituations":"Split-brain or archived-log truncation leaving nodes at divergent positions; archive replay ended at a different position than the new leader is streaming from; misconfigured archive/log channels causing the wrong image to be joined.","solutions":["Ensure the node replays logs fully from the archive before attempting leadership extension.","Check for split-brain: verify quorum and remove any falsely-elected leader.","Confirm archive/log channel configurations are identical across all cluster nodes.","Restart the node from a consistent snapshot so its logPosition aligns with the cluster."],"exampleFix":"// before: election triggered while replay incomplete\n// after: wait for replay to finish before offering leadership\nwhile (replayPosition < stopPosition) { agent.doWork(); }","handlingStrategy":"validation","validationCode":"// after replay, before election completes\nlong joinPos = subscription.imageAtIndex(0).joinPosition();\nif (joinPos != consensusModule.logPosition()) { rejoinElection(); }","typeGuard":null,"tryCatchPattern":"try { agent.doWork(); } catch (ClusterException e) { if (e.getMessage().contains(\"joinPosition\") && e.getMessage().contains(\"logPosition\")) { triggerElectionRestart(); } else { throw e; } }","preventionTips":["Ensure full archive replay before leadership transitions.","Eliminate split-brain risks with correct quorum configuration.","Keep log/archive channels consistent across nodes."],"tags":["leader-election","log-position","cluster","consistency"],"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-19T12:17:13.211Z"}