aeron-io/aeron · error · ClusterEvent

unexpected recording stop during catchup: position=

Error message

unexpected recording stop during catchup: position=<position>

What it means

During log catch-up the follower tracks how far the recording has been appended via appendPosition. If the recording stops (appendPosition becomes null) while the node is still ACTIVE or SUSPENDED and catching up, the agent throws ClusterEvent because catch-up can no longer make progress.

Solutions

  1. Ensure the leader keeps recording until all followers complete catch-up (check recording lifecycle and aeron.archive settings).
  2. Investigate archive agent logs for why the recording stopped (disk full, archive crash).
  3. Retry election/catch-up — the cluster will typically re-elect and request the recording again.
  4. Increase archive storage capacity and monitor recording continuity on the leader.

Example fix

// before: leader stops recording as soon as it commits
// after: leader retains recording until min follower position >= recording end
if (minFollowerPosition < recordingStopPosition) { keepRecording(); }
Defensive patterns

Strategy: retry

Validate before calling

// before catchup
if (!archive.isRecordingActive(recordingId)) { triggerElectionRestart(); }

Try / catch

try { agent.doWork(); } catch (ClusterEvent e) { if (e.getMessage().contains("unexpected recording stop during catchup")) { restartCatchupOrElection(); } else { throw e; } }

Prevention

When it happens

Trigger: In catchup(), appendPosition is null (recording stopped / recording signal lost) while state is ACTIVE or SUSPENDED, meaning the archive recording being followed terminated before the node caught up.

Common situations: Leader/recording stopped while a slow follower was still catching up; archive recording ended prematurely (disk full, archive agent crash); membership change removing the source recording mid-catchup.

Related errors


AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12). Data as JSON: /api/errors/82b12d874f051819. Report an issue: GitHub.

Appendix: source

Thrown at aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModuleAgent.java:1984

            }
        }
    }

    void catchupInitiated(final long nowNs)
    {
        timeOfLastAppendPositionUpdateNs = nowNs;
        timeOfLastAppendPositionSendNs = nowNs;
    }

    int catchupPoll(final long limitPosition, final long nowNs)
    {
        int workCount = 0;

        if (ConsensusModule.State.ACTIVE == state || ConsensusModule.State.SUSPENDED == state)
        {
            if (null == appendPosition)
            {
                throw new ClusterEvent(
                    "unexpected recording stop during catchup: position=" + logAdapter.position());
            }

            final long currentAppendPosition = appendPosition.get();
            final int fragments = logAdapter.poll(min(currentAppendPosition, limitPosition));
            workCount += fragments;
            if (0 == fragments && logAdapter.isImageClosed())
            {
                throw new ClusterEvent(
                    "unexpected image close during catchup: position=" + logAdapter.position());
            }

            workCount += updateFollowerPosition(
                election.leader().publication(),
                nowNs,
                leadershipTermId,
                currentAppendPosition,
                APPEND_POSITION_FLAG_CATCHUP);

View on GitHub (pinned to 6d60124e15)