aeron-io/aeron · error · ClusterException
expected schemaId=<MessageHeaderDecoder.SCHEMA_ID>, actual=
Error message
expected schemaId=<MessageHeaderDecoder.SCHEMA_ID>, actual=<schemaId>
What it means
ControlledEgressAdapter.onFragment decoded the SBE MessageHeader of an egress fragment and found a schemaId that does not match the cluster egress schema (MessageHeaderDecoder.SCHEMA_ID). The library throws ClusterException because it cannot safely decode the message body with the compiled codecs.
Solutions
- Ensure client and cluster use the same aeron-cluster version so SBE schema IDs match
- Verify the subscription is bound to the cluster's egress channel/stream, not an unrelated stream
- Regenerate SBE codecs from the matching aeron-cluster-schema.xml if schemas were customized
- Log the actual schemaId to identify which schema produced the fragment
Example fix
// before: mixed versions // client: aeron-cluster 1.40.0, cluster: 1.44.0 // after: align versions // client and cluster both on aeron-cluster 1.44.0
Defensive patterns
Strategy: validation
Validate before calling
// Check header schemaId before offering fragment to the adapter
MessageHeaderDecoder h = new MessageHeaderDecoder().wrap(buffer, offset);
if (h.schemaId() != MessageHeaderDecoder.SCHEMA_ID) {
// skip/log instead of calling adapter
} Try / catch
try {
adapter.onFragment(buffer, offset, length, header);
} catch (ClusterException ex) {
// log schema mismatch, investigate version skew
} Prevention
- Pin identical aeron-cluster versions on client and cluster
- Never publish non-cluster messages on the egress stream
- Verify streamId/channel wiring in tests
When it happens
Trigger: Feeding the adapter a fragment from a stream carrying a different SBE schema (wrong stream/subscription wiring); cluster and client built against different aeron-cluster versions with mismatched schema IDs.
Common situations: Client pointing at the wrong image/publication; mixed Aeron versions between cluster and client after an upgrade; custom messages published onto the egress channel.
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=<MessageHeaderDecoder.SCHEMA_ID>, actual=
- expected schemaId= , actual=
- expected schemaId=<MessageHeaderDecoder.SCHEMA_ID>, actual=
- expected schemaId= , actual=
- expected schemaId= , actual=
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/84b54f7e28a4d33c.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-cluster/src/main/java/io/aeron/cluster/client/ControlledEgressAdapter.java:122
{
messageHeaderDecoder.wrap(buffer, offset);
final int templateId = messageHeaderDecoder.templateId();
final int schemaId = messageHeaderDecoder.schemaId();
if (schemaId != MessageHeaderDecoder.SCHEMA_ID)
{
if (listenerExtension != null)
{
return listenerExtension.onExtensionMessage(
messageHeaderDecoder.blockLength(),
templateId,
schemaId,
messageHeaderDecoder.version(),
buffer,
offset + MessageHeaderDecoder.ENCODED_LENGTH,
length - MessageHeaderDecoder.ENCODED_LENGTH);
}
throw new ClusterException("expected 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)
{
return listener.onMessage(
sessionId,View on GitHub (pinned to 6d60124e15)