aeron-io/aeron · error · ArchiveException

unexpected response code

Error message

unexpected response code: <code>

What it means

Thrown by awaitRelevantId (and similar response awaiters) when the archive replies for the expected correlationId with a control response whose code is not OK. The ArchiveException message carries the ControlResponseCode value, and relevantId/error details on the poller explain the underlying rejection.

Solutions

  1. Inspect the ArchiveException error code (e.errorCode()) and the archive log for the root cause of the non-OK response.
  2. Validate the recordingId exists (listRecording) before operations that expect an OK response.
  3. Ensure client and archive versions are compatible (same protocol version).
  4. Handle expected error codes explicitly rather than treating every non-OK as fatal.

Example fix

// before
int sessionId = archive.startReplay(recordingId, position, length, replayChannel, replayStreamId);
// after
try {
    int sessionId = archive.startReplay(recordingId, position, length, replayChannel, replayStreamId);
} catch (ArchiveException e) {
    if (e.errorCode() == ArchiveException.UNKNOWN_RECORDING) {
        // verify recording exists / was purged
    }
    throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// verify recording exists before replay
archive.listRecording(recordingId); // throws RecordingSignal/position errors if absent

Try / catch

try {
    int session = archive.startReplay(recordingId, pos, len, ch, streamId);
} catch (ArchiveException e) {
    if (e.errorCode() == ArchiveException.UNKNOWN_RECORDING) { /* handle */ }
    else throw e;
}

Prevention

When it happens

Trigger: Any call using awaitRelevantId (e.g. startReplay returning replay sessionId) where the archive responds with ERROR or an unexpected code for the matched correlationId - e.g. unknown recordingId, no available replay, or session errors.

Common situations: Requesting a replay for a deleted/unknown recording; archive rejecting a request due to exhausted replay resources; protocol/version mismatch between client and archive producing an unrecognized code.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at aeron-archive/src/main/java/io/aeron/archive/client/AeronArchive.java:2443

                final ArchiveException ex = new ArchiveException(
                    "response for correlationId=" + correlationId + ", error: " + poller.errorMessage(),
                    (int)poller.relevantId(),
                    poller.correlationId());

                if (poller.correlationId() == correlationId)
                {
                    throw ex;
                }
                else if (context.errorHandler() != null)
                {
                    context.errorHandler().onError(ex);
                }
            }
            else if (poller.correlationId() == correlationId)
            {
                if (ControlResponseCode.OK != code)
                {
                    throw new ArchiveException("unexpected response code: " + code);
                }

                return poller.relevantId();
            }
        }
    }

    private boolean pollForResponseAllowingError(final long correlationId, final int allowedErrorCode)
    {
        final long deadlineNs = nanoClock.nanoTime() + messageTimeoutNs;
        final ControlResponsePoller poller = controlResponsePoller;

        while (true)
        {
            pollNextResponse(correlationId, deadlineNs, poller);

            if (poller.controlSessionId() != controlSessionId)
            {

View on GitHub (pinned to 6d60124e15)