aeron-io/aeron · critical · ClusterEvent
new leader detected due to commit position - memberId=
Error message
new leader detected due to commit position - memberId=${memberId} this.leadershipTermId=${leadershipTermId} this.leaderMemberId=${leaderMemberId} this.logPosition=${logPosition} newLeadershipTermId=${newLeadershipTermId} newLeaderMemberId=${newLeaderMemberId} newCommitPosition=${newCommitPosition}) What it means
In onCommitPosition, a member in LEADER_READY state receives a commit position for a leadershipTermId greater than its own — proof that another member is already leading a newer term. The member believed it was leader but has been superseded, so it throws ClusterEvent to abort the stale leadership.
Solutions
- Increase leaderHeartbeatTimeoutNs / election timeouts to tolerate pauses and slow networks
- Check for GC pauses or host suspensions on the affected node
- Ensure NTP-synchronized clocks across members
- Restart the member to rejoin cleanly under the newer leader; upgrade Aeron for improved election dedup logic
Example fix
// before: brief GC pause causes competing leadership ClusterEvent: new leader detected due to commit position - memberId=1 this.leadershipTermId=5 ... // after ctx.leaderHeartbeatTimeoutNs(TimeUnit.SECONDS.toNanos(15)); // longer heartbeat tolerance electionTimeoutNs similarly increased
Defensive patterns
Strategy: retry
Validate before calling
// Tune timeouts up-front so paused nodes don't spuriously lose/claim leadership long hbTimeout = TimeUnit.SECONDS.toNanos(15); // > worst-case GC/host pause
Try / catch
try {
cluster.start();
} catch (ClusterEvent e) {
if (e.getMessage().startsWith("new leader detected due to commit position")) {
// rejoin under the newer leader: restart the member
restartAndRejoin();
} else { throw e; }
} Prevention
- Set leaderHeartbeatTimeoutNs generously above max pause times
- Sync clocks via NTP across all members
- Investigate GC/host pauses on nodes reporting this event
When it happens
Trigger: A member won an election and entered LEADER_READY, then received a commit position from a different leader with a higher leadershipTermId — two members briefly believed they were leader (expired votes, slow heartbeats) or a higher-term leader emerged while this node's election completion was delayed.
Common situations: Network partitions resolved with two competing leaders; heartbeat timeouts too short causing spurious elections; node suspension (GC/VM pause) causing it to miss its win and lose to a new term; clock skew across members.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- unexpected image close during catchup: position=
- election in progress
- logSessionId was null, should always have a value
- potential new election in progress
- invalid newLeadershipTerm - this.appendPosition=
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/95ab3d1a0ceeed6b.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-cluster/src/main/java/io/aeron/cluster/Election.java:578
if (INIT == state)
{
return;
}
// we do not check `leadershipTermId == this.leadershipTermId` here, because prior to fixes the leader was
// sending wrong `leadershipTermId` value in the `CommitPosition` message (i.e. not matching the one sent
// by the `NewLeadershipTerm` message).
if (null != leaderMember && leaderMember.id() == leaderMemberId)
{
notifiedCommitPosition = max(notifiedCommitPosition, logPosition);
if (FOLLOWER_LOG_REPLICATION == state)
{
replicationDeadlineNs = nowNs(ctx) + ctx.leaderHeartbeatTimeoutNs();
}
}
else if (leadershipTermId > this.leadershipTermId && LEADER_READY == state)
{
throw new ClusterEvent("new leader detected due to commit position - " +
" memberId=" + thisMemberId() +
" this.leadershipTermId=" + this.leadershipTermId +
" this.leaderMemberId=" + (null != leaderMember ? leaderMember.id() : NULL_VALUE) +
" this.logPosition=" + this.logPosition +
" newLeadershipTermId=" + leadershipTermId +
" newLeaderMemberId=" + leaderMemberId +
" newCommitPosition=" + logPosition +
")");
}
}
void onReplayNewLeadershipTermEvent(
final long leadershipTermId,
final long logPosition,
final long timestamp,
final long termBaseLogPosition)
{
if (INIT == state)View on GitHub (pinned to 6d60124e15)