aeron-io/aeron · error · ClusterException

Live log replay failed

Error message

Live log replay failed: ${poller.code()}

What it means

During live log replay the agent polls archive control responses via a ControlResponsePoller. Allowed outcomes advance the state; an ERROR delegates to a detailed exception, and any other unexpected response code makes the agent throw ClusterException 'Live log replay failed: <code>'.

Solutions

  1. Check archive logs for the control interaction that produced the unexpected code.
  2. Align the archive client version with the archive server (control protocol change).
  3. Retry the backup; if persistent, inspect poller.code() against ControlResponseCode and fix archive configuration.
Defensive patterns

Strategy: retry

Validate before calling

// pre-check archive reachable and recording present before backup
archiveClient.listRecordings(0, 10, (c, i) -> {}, (c, i) -> {});

Try / catch

try { ClusterBackup.launch(ctx); } catch (ClusterException e) { if (e.getMessage().startsWith("Live log replay failed")) { scheduleRetryWithBackoff(); } }

Prevention

When it happens

Trigger: The archive control poller returns a response code the replay state machine does not expect (not OK, ERROR, or the replay-session code) while awaiting live log replay for the backup.

Common situations: Archive returning protocol responses from a mismatched archive version; unexpected control channel traffic; archive misconfiguration serving the wrong recording.

Related errors


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

Appendix: source

Thrown at aeron-cluster/src/main/java/io/aeron/cluster/ClusterBackupAgent.java:869

                }
            }
            else if (NULL_VALUE == liveLogReplaySessionId)
            {
                final ControlResponsePoller poller = clusterArchive.controlResponsePoller();
                if (0 != poller.poll() && poller.isPollComplete() &&
                    poller.controlSessionId() == clusterArchive.controlSessionId() &&
                    poller.correlationId() == correlationId)
                {
                    switch (poller.code())
                    {
                        case OK ->
                        {
                            liveLogReplaySessionId = poller.relevantId();
                            timeOfLastProgressMs = nowMs;
                            workCount++;
                        }
                        case ERROR -> throwReplayFailedException(poller);
                        default -> throw new ClusterException("Live log replay failed: " + poller.code());
                    }
                }
            }
            else if (NULL_COUNTER_ID == liveLogRecordingCounterId)
            {
                final CountersReader countersReader = aeron.countersReader();

                liveLogRecordingCounterId = RecordingPos.findCounterIdBySession(
                    countersReader, (int)liveLogReplaySessionId, backupArchive.archiveId());
                if (NULL_COUNTER_ID != liveLogRecordingCounterId)
                {
                    liveLogPositionCounter.setRelease(countersReader.getCounterValue(liveLogRecordingCounterId));
                    liveLogRecordingId = RecordingPos.getRecordingId(countersReader, liveLogRecordingCounterId);
                    timeOfLastBackupQueryMs = nowMs;
                    timeOfLastProgressMs = nowMs;
                    state(UPDATE_RECORDING_LOG, nowMs);
                    workCount++;
                }

View on GitHub (pinned to 6d60124e15)