aeron-io/aeron · error · ArchiveException
expected schemaId=
Error message
expected schemaId=
What it means
AsyncAeronArchive.ControlResponseFragmentHandler.onFragment wraps the incoming buffer with the SBE MessageHeaderDecoder and throws ArchiveException when the decoded schemaId does not match the archive control-protocol schema id. The fragment on the control-response channel is not a valid archive control message, so it cannot be safely decoded.
Solutions
- Align the aeron-archive client and archive server versions so both use the same SBE schema id
- Ensure only the archive publishes on the control-response channel/stream you subscribed to
- Verify channel/stream configuration: the control response subscription should not carry unrelated traffic
- Clean build to avoid stale generated SBE codecs from a different schema version on the classpath
Example fix
// before
AeronArchive.connect(new AeronArchive.Context().controlResponseChannel("aeron:udp?endpoint=localhost:8010"));
// ...server on a different protocol version
// after
// pin matching versions
dependencies {
implementation("io.aeron:aeron-archive:1.44.1") // same as archive server
} Defensive patterns
Strategy: validation
Validate before calling
MessageHeaderDecoder h = new MessageHeaderDecoder().wrap(buffer, offset);
if (h.schemaId() != MessageHeaderDecoder.SCHEMA_ID) {
throw new IllegalStateException("foreign message on control stream, schemaId=" + h.schemaId());
} Type guard
boolean isArchiveControlSchema(DirectBuffer buf, int offset) {
return new MessageHeaderDecoder().wrap(buf, offset).schemaId() == MessageHeaderDecoder.SCHEMA_ID;
} Try / catch
try {
asyncArchive.pollResponses();
} catch (ArchiveException e) {
if (e.getMessage().startsWith("expected schemaId=")) {
log.warn("non-archive traffic on control stream; check versions/publishers", e);
}
} Prevention
- Pin identical aeron-archive versions on client and server
- Never publish application messages on the archive control-response stream
- Clean builds to avoid stale generated SBE codecs on the classpath
- Log schemaId/templateId of unexpected fragments to identify the foreign source
When it happens
Trigger: onFragment receives a buffer whose MessageHeaderDecoder.schemaId() differs from MessageHeaderDecoder.SCHEMA_ID — e.g. a foreign SBE-encoded message published onto the control-response stream, a mismatched archive client/server protocol version, or corrupted/interleaved traffic on the control channel.
Common situations: Pointing a client built against one aeron-archive version at an archive running a different SBE schema; another application publishing onto the same control-response stream/channel; stale jar mixing after an upgrade.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/98e9fb51daebe4a8.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-archive/src/main/java/io/aeron/archive/client/AsyncAeronArchive.java:295
{
state = State.CLOSED;
CloseHelper.quietCloseAll(asyncConnect, aeronArchive);
}
}
private ControlledFragmentHandler.Action onFragment(
final DirectBuffer buffer,
final int offset,
final int length,
final Header header)
{
messageHeaderDecoder.wrap(buffer, offset);
final int schemaId = messageHeaderDecoder.schemaId();
if (schemaId != MessageHeaderDecoder.SCHEMA_ID)
{
throw new ArchiveException("expected schemaId=" + MessageHeaderDecoder.SCHEMA_ID + ", actual=" + schemaId);
}
final int templateId = messageHeaderDecoder.templateId();
switch (templateId)
{
case ControlResponseDecoder.TEMPLATE_ID:
controlResponseDecoder.wrap(
buffer,
offset + MessageHeaderEncoder.ENCODED_LENGTH,
messageHeaderDecoder.blockLength(),
messageHeaderDecoder.version());
if (controlResponseDecoder.controlSessionId() == controlSessionId)
{
listener.onControlResponse(
controlResponseDecoder.correlationId(),
controlResponseDecoder.relevantId(),
controlResponseDecoder.code(),View on GitHub (pinned to 6d60124e15)