aeron-io/aeron · warning · TimeoutException
failed to join catchup log
Error message
failed to join catchup log
What it means
TimeoutException (WARN) thrown when the follower fails to reach the point of joining the catchup log at all: before any subscription progress is observed, the leaderHeartbeatTimeoutNs window expires. It is the outer, earlier failure mode of the catchup join compared to "failed to join catchup log as follower".
Solutions
- Check whether a valid leader exists at all (cluster may be stuck canvassing); inspect election logs on all members
- Fix member channel configuration so replay traffic can flow
- Increase leaderHeartbeatTimeoutNs if the environment is legitimately slow
- Restart the node to re-enter canvass and retry the election
Defensive patterns
Strategy: retry
Validate before calling
// ensure a quorum of members is up before expecting elections to complete
if (liveMembers() < quorumSize()) {
LOG.warn("no quorum; catchup joins will time out");
} Try / catch
catch (TimeoutException e) {
// outer catchup timeout; verify leader existence then re-enter election
} Prevention
- Run at least quorum+1 members for fault tolerance
- Monitor cluster canvass state
- Keep replay channels configured identically on all members
When it happens
Trigger: followerCatchupInit in an early branch: neither the catchup position send nor a subscription state change happened within timeOfLastStateChangeNs + ctx.leaderHeartbeatTimeoutNs().
Common situations: Leader election stalled because candidate leader never responded; total network outage; misconfigured replay channel so no traffic ever flows; watchdog pauses on the follower.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
Related errors
- startupCanvassTimeoutNs=
- unexpected image close during catchup: position=
- no catchup progress: commitPosition=
- timeout awaiting commit position
- failed to send catchup position
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/7658d94179134497.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-cluster/src/main/java/io/aeron/cluster/Election.java:1083
verifyLogJoinPosition("followerCatchupAwait", image.joinPosition());
if (consensusModuleAgent.tryJoinLogAsFollower(image, isLeaderStartup, nowNs))
{
state(FOLLOWER_CATCHUP, nowNs, "");
workCount++;
}
else if (ChannelEndpointStatus.ERRORED == logSubscription.channelStatus())
{
final String message = "failed to add catchup log as follower - " + logSubscription.channel();
throw new ClusterException(message, AeronException.Category.WARN);
}
else if (nowNs >= (timeOfLastStateChangeNs + ctx.leaderHeartbeatTimeoutNs()))
{
throw new TimeoutException("failed to join catchup log as follower", AeronException.Category.WARN);
}
}
else if (nowNs >= (timeOfLastStateChangeNs + ctx.leaderHeartbeatTimeoutNs()))
{
throw new TimeoutException("failed to join catchup log", AeronException.Category.WARN);
}
return workCount;
}
private int followerCatchup(final long nowNs)
{
int workCount = consensusModuleAgent.catchupPoll(notifiedCommitPosition, nowNs);
if (null == consensusModuleAgent.liveLogDestination() &&
consensusModuleAgent.isCatchupNearLive(max(catchupJoinPosition, notifiedCommitPosition)))
{
addLiveLogDestination();
workCount++;
}
final long position = ctx.commitPositionCounter().getPlain();
if (position >= catchupJoinPosition &&View on GitHub (pinned to 6d60124e15)