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
- Align client and archive versions — upgrade aeron-archive/aeron-all on both sides so response codes are understood.
- Log the numeric code and correlationId from the ArchiveException to identify which message produced the unrecognized reply.
- Check for multiple archives on the same control response channel (aliased endpoints) mixing replies into your subscription.
- 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
- Keep aeron-archive client and archive server on the same release train.
- Log the numeric response code and correlationId to trace the offending message.
- Isolate the control response channel per client so foreign replies cannot mix in.
- Avoid protocol extensions unless the client poller is updated to handle the new codes.
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
- mark file ( ) major version does not match software
- Aeron client instance must set…
- Aeron client must use a RethrowingErrorHandler
- segment file length not a power of 2
- segment file length not in valid range
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)