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

  1. Increase leaderHeartbeatTimeoutNs / election timeouts to tolerate pauses and slow networks
  2. Check for GC pauses or host suspensions on the affected node
  3. Ensure NTP-synchronized clocks across members
  4. 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

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


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)