aeron-io/aeron · error · ClusterException
expected cluster egress…
Error message
expected cluster egress schemaId=<MessageHeaderDecoder.SCHEMA_ID> actual=<schemaId>
What it means
onFragment decodes each egress fragment's SBE MessageHeader and validates that schemaId equals MessageHeaderDecoder.SCHEMA_ID for the cluster egress schema. A different schemaId means the fragment is not cluster egress data of the expected schema, so the library throws ClusterException rather than misinterpreting the buffer.
Solutions
- Ensure client and cluster run Aeron versions with the same cluster egress SBE schema id; upgrade/restart both sides together.
- Verify the egress Subscription channel/streamId is dedicated to cluster egress and not shared with other publishers.
- Check for stale processes on the egress endpoint publishing old-schema messages.
- Catch ClusterException in egress handlers and log schemaId to identify the offending publisher.
Example fix
// before
final int schemaId = headerDecoder.schemaId(); // throws later if unexpected
// after
if (headerDecoder.schemaId() != MessageHeaderDecoder.SCHEMA_ID) { logMismatchAndDropFragment(headerDecoder.schemaId()); return; } Defensive patterns
Strategy: validation
Validate before calling
if (messageHeaderDecoder.schemaId() != MessageHeaderDecoder.SCHEMA_ID) { log.error("unexpected egress schemaId " + messageHeaderDecoder.schemaId()); return; } Try / catch
try { egressSubscription.poll(client::onFragment, 1); } catch (ClusterException e) { if (e.getMessage().contains("expected cluster egress schemaId")) { haltAndCheckVersionMismatch(); } } Prevention
- Deploy client and cluster with matching Aeron/SBE schema versions.
- Dedicate the egress channel/streamId to the cluster only.
- Log and inspect schemaId on any non-conforming egress traffic.
When it happens
Trigger: Polling the client's egress subscription (onFragment) with an image whose data was produced against a different SBE schema version — e.g. a cluster running a different Aeron/SBE schema than the client library, or the subscription receiving unrelated traffic on the same channel/stream.
Common situations: Client and server Aeron versions mismatched after an upgrade; egress stream shared with other applications publishing non-egress messages; binary-stale deployments where one side was not restarted.
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
- expected schemaId= , actual=
- expected schemaId= , actual=
- expected schemaId= , actual=
- expected schemaId= , actual=
- invalid clusterSessionId= expected=
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/fdba01936816d738.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-cluster/src/main/java/io/aeron/cluster/client/AeronCluster.java:865
final int schemaId = messageHeaderDecoder.schemaId();
final int templateId = messageHeaderDecoder.templateId();
if (schemaId != MessageHeaderDecoder.SCHEMA_ID)
{
if (egressListenerExtension != null)
{
egressListenerExtension.onExtensionMessage(
messageHeaderDecoder.blockLength(),
templateId,
schemaId,
messageHeaderDecoder.version(),
buffer,
offset + MessageHeaderDecoder.ENCODED_LENGTH,
length - MessageHeaderDecoder.ENCODED_LENGTH);
}
else
{
throw new ClusterException(
"expected cluster egress schemaId=" + MessageHeaderDecoder.SCHEMA_ID + " actual=" + schemaId);
}
}
switch (templateId)
{
case SessionMessageHeaderDecoder.TEMPLATE_ID:
{
sessionMessageHeaderDecoder.wrap(
buffer,
offset + MessageHeaderDecoder.ENCODED_LENGTH,
messageHeaderDecoder.blockLength(),
messageHeaderDecoder.version());
final long sessionId = sessionMessageHeaderDecoder.clusterSessionId();
if (sessionId == clusterSessionId)
{
egressListener.onMessage(View on GitHub (pinned to 6d60124e15)