{"record":{"id":"93c4597a41628e7a","repo":"aeron-io/aeron","slug":"state-joinposition-joinposition-inequality-than-logposition","errorCode":null,"errorMessage":"${state} - joinPosition=${joinPosition}${inequality}than logPosition=${logPosition}","messagePattern":"(.+?) - joinPosition=(.+?)(.+?)than logPosition=(.+?)","errorType":"exception","errorClass":"ClusterEvent","httpStatus":null,"severity":"critical","filePath":"aeron-cluster/src/main/java/io/aeron/cluster/Election.java","lineNumber":1544,"sourceCode":"        logLeadershipTermId = leadershipTermId;\n    }\n\n    private void updateRecordingLogForReplication(\n        final long leadershipTermId,\n        final long termBaseLogPosition,\n        final long logPosition,\n        final long nowNs)\n    {\n        ensureRecordingLogCoherent(leadershipTermId, termBaseLogPosition, logPosition, nowNs);\n        logLeadershipTermId = leadershipTermId;\n    }\n\n    private void verifyLogJoinPosition(final String state, final long joinPosition)\n    {\n        if (joinPosition != logPosition)\n        {\n            final String inequality = joinPosition < logPosition ? \" less \" : \" greater \";\n            throw new ClusterEvent(\n                state + \" - joinPosition=\" + joinPosition + inequality + \"than logPosition=\" + logPosition);\n        }\n    }\n\n    private boolean hasUpdateIntervalExpired(final long nowNs, final long intervalNs)\n    {\n        return hasIntervalExpired(nowNs, timeOfLastUpdateNs, intervalNs);\n    }\n\n    private boolean hasIntervalExpired(\n        final long nowNs, final long previousTimestampForIntervalNs, final long intervalNs)\n    {\n        return (nowNs - previousTimestampForIntervalNs) >= intervalNs;\n    }\n\n    private void logStateChange(\n        final int memberId,\n        final ElectionState oldState,","sourceCodeStart":1526,"sourceCodeEnd":1562,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-cluster/src/main/java/io/aeron/cluster/Election.java#L1526-L1562","documentation":"Election.verifyLogJoinPosition guards that the position at which a member is asked to join (or replay) the cluster log exactly equals the member's current logPosition. Aeron requires the log to be joined at the exact committed position so no entries are skipped or duplicated; any mismatch is a consensus/follower state bug and the election is aborted with a ClusterEvent.","triggerScenarios":"During election states such as FOLLOWER_BALLOT, CATCHUP_TRANSITION or LEADER_TRANSITION, Election computes a joinPosition passed to verifyLogJoinPosition; if it differs from this member's logPosition (because of stale snapshot state, a catchup that did not complete, or an internal bookkeeping bug), the exception is thrown.","commonSituations":"Corrupt or outdated snapshot/recovery state on a member, interrupted catch-up, versions of the cluster members out of sync, or a bug in custom election/consensus-module extensions leading members to disagree on the log position.","solutions":["Check the reported joinPosition vs logPosition values to see which member state is stale","Restore the member from a recent snapshot or clean its cluster data directory and rejoin so it recovers via catch-up","Ensure all members run the same Aeron version and cluster configuration (term-length, service Counters)","If reproducible, file a bug with the election state trace — a mismatch here usually indicates an internal election bug"],"exampleFix":"// before: joining log with a computed position\nctx.logChannel() // joined with joinPosition != election.logPosition\n// after: force the member to catch up before joining\nif (joinPosition != logPosition) {\n    // re-enter catch-up / reset from snapshot instead of throwing\n    electionState(ElectionState.CATCHUP_TRANSITION);\n}","handlingStrategy":"try-catch","validationCode":"if (election.logPosition() != expectedJoinPosition) { /* re-enter catch-up instead of joining */ }","typeGuard":null,"tryCatchPattern":"try { election.joinLog(joinPosition); } catch (ClusterEvent e) { agent.resetFromSnapshot(); }","preventionTips":["Keep snapshots and recovery state up to date on every member","Run identical Aeron versions across the cluster","Monitor catch-up completion before log join"],"tags":["aeron-cluster","election","consensus","log-position"],"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"}