aeron-io/aeron · error · ClusterEvent

unexpected image close when replaying log: position=

Error message

unexpected image close when replaying log: position=<position>

What it means

While a follower is replaying the log from the archive, the replay image can close prematurely (recording/image ended before reaching stopPosition). The agent throws ClusterEvent to signal the replay cannot be completed, which typically triggers a retry of the log replay or election restart.

Solutions

  1. Verify the archive recording covering the full log range exists and was not deleted (recording log / aeron-archive tooling).
  2. Retry the election/replay — the cluster usually re-elects and re-requests the replay.
  3. Check archive client and network stability between follower and archive/leader.
  4. Increase archive retention so recordings outlive follower catch-up windows.

Example fix

// before: recordings pruned aggressively
archive.markCatalog... delete old recordings while followers still need them
// after: retain recordings until all followers have caught up past that position
Defensive patterns

Strategy: retry

Validate before calling

// before requesting replay
if (!archive.hasRecordingForRange(logPosition, stopPosition)) { electDifferentLeader(); }

Try / catch

try { agent.doWork(); } catch (ClusterEvent e) { if (e.getMessage().contains("unexpected image close when replaying log")) { requestReplayAgain(); } else { throw e; } }

Prevention

When it happens

Trigger: During log replay, logAdapter.isImageClosed() becomes true while commit position is still below stopPosition — the archive replay image ended early because the recording stopped or the archive connection dropped.

Common situations: Archive recording deleted or stopped before all followers caught up; archive agent/network failure severing the replay subscription; leader crashed and its recording became unavailable mid-replay.

Related errors


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

Appendix: source

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

        return new LogReplay(archive, logRecordingId, logPosition, appendPosition, logAdapter, ctx);
    }

    int replayLogPoll(final LogAdapter logAdapter, final long stopPosition)
    {
        int workCount = 0;

        if (ConsensusModule.State.ACTIVE == state || ConsensusModule.State.SUSPENDED == state)
        {
            logAdapter.poll(stopPosition);
            final long position = logAdapter.position();

            if (commitPosition.proposeMaxRelease(position))
            {
                workCount++;
            }
            else if (logAdapter.isImageClosed() && position < stopPosition)
            {
                throw new ClusterEvent("unexpected image close when replaying log: position=" + position);
            }
        }

        workCount += consensusModuleAdapter.poll();

        return workCount;
    }

    long logRecordingId()
    {
        return logRecordingId;
    }

    void logRecordingId(final long recordingId)
    {
        if (NULL_VALUE != recordingId)
        {
            logRecordingId = recordingId;

View on GitHub (pinned to 6d60124e15)