aeron-io/aeron · error · ArchiveException

unexpected response: code=

Error message

unexpected response: code=

What it means

While awaiting a control response, the client reads the response code from the ControlResponsePoller. If a response with an error/invalid code arrives without a usable errorMessage (so the normal ArchiveException(errorMessage, errorCode) path is skipped), the library throws ArchiveException('unexpected response: code=<code>') tagged as Category.ERROR with the correlationId, indicating an unrecognized archive reply.

Solutions

  1. Align client and archive versions — upgrade aeron-archive/aeron-all on both sides so response codes are understood.
  2. Log the numeric code and correlationId from the ArchiveException to identify which message produced the unrecognized reply.
  3. Check for multiple archives on the same control response channel (aliased endpoints) mixing replies into your subscription.
  4. If you extended the protocol, add handling for the new code in the client poller/await loop.

Example fix

// before
// client built against aeron 1.40 talking to archive 1.44 with new response codes
// after
// upgrade the client dependency to match the archive:
// <dependency><artifactId>aeron-archive</artifactId><version>1.44.1</version></dependency>
Defensive patterns

Strategy: try-catch

Validate before calling

// check version compatibility at startup
// compare AeronArchive.Configuration protocol/version info with the archive's via ControlResponsePoller version events

Try / catch

try { archive.awaitResponse(correlationId); } catch (ArchiveException e) { log.error("unexpected archive response code=" + e.getMessage() + " corrId=" + e.correlationId()); }

Prevention

When it happens

Trigger: The archive (or an intermediary) sends a control response with a code the client does not handle — e.g. a newer archive protocol version introducing a new ControlResponseCode, or a corrupted/mismatched response correlation leading the client to process a foreign message.

Common situations: Running a client older than the archive (protocol drift); connecting to the wrong archive that emits different response semantics; custom extensions to the protocol on the archive side.

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/3b3ef2bb59ede951. Report an issue: GitHub.

Appendix: source

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

                    correlationId = ctx.aeron().nextCorrelationId();
                    state(State.SEND_CHALLENGE_RESPONSE);
                }
                else
                {
                    final ControlResponseCode code = controlResponsePoller.code();
                    if (ControlResponseCode.OK != code)
                    {
                        archiveProxy.closeSession(controlSessionId);
                        if (ControlResponseCode.ERROR == code)
                        {
                            final String errorMessage = controlResponsePoller.errorMessage();
                            final int errorCode = (int)controlResponsePoller.relevantId();

                            throw new ArchiveException(errorMessage, errorCode, correlationId);
                        }

                        throw new ArchiveException(
                            "unexpected response: code=" + code, correlationId, AeronException.Category.ERROR);
                    }

                    if (State.AWAIT_ARCHIVE_ID_RESPONSE == state)
                    {
                        final long archiveId = controlResponsePoller.relevantId();
                        aeronArchive = transitionToDone(archiveId);
                    }
                    else
                    {
                        final int archiveProtocolVersion = controlResponsePoller.version();
                        if (archiveProtocolVersion < PROTOCOL_VERSION_WITH_ARCHIVE_ID)
                        {
                            aeronArchive = transitionToDone(NULL_VALUE);
                        }
                        else
                        {
                            correlationId = ctx.aeron().nextCorrelationId();

View on GitHub (pinned to 6d60124e15)