aeron-io/aeron · critical · ClusterException
expected schemaId= , actual=
Error message
expected schemaId=<SCHEMA_ID>, actual=<schemaId>
What it means
ConsensusModuleAdapter.onFragment validates that the SBE message header of every incoming fragment carries the expected schema id (MessageHeaderDecoder.SCHEMA_ID). A mismatch means the sender encoded messages with a different SBE schema, so decoding would produce garbage. The library throws immediately to fail fast rather than misinterpret cluster protocol messages.
Solutions
- Run the same Aeron version on every cluster node so all nodes share identical SBE schema ids.
- Verify nothing else (services, tests, probes) is publishing onto the cluster/consensus module transport channel.
- Rebuild cleanly to eliminate stale or conflicting aeron-cluster codec jars on the classpath.
- Check message archives/logs replayed into the cluster were produced with the same schema version.
Example fix
// before: cluster mixes node versions -Daeron.cluster.dir=... // node on aeron 1.40, others on 1.44 // after: align versions every node uses identical aeron artifacts, cluster restarts cleanly
Defensive patterns
Strategy: validation
Validate before calling
// before joining the cluster, assert codec schema consistency
if (MessageHeaderDecoder.SCHEMA_ID != expectedClusterSchemaId) {
throw new IllegalStateException("codec schema id mismatch: rebuild against the cluster's SBE schema");
} Try / catch
try { agent.doWork(); } catch (ClusterException e) { if (e.getMessage().contains("expected schemaId")) { haltAndRejoinWithMatchingVersion(); } else { throw e; } } Prevention
- Pin identical Aeron versions across all cluster nodes.
- Never publish application messages on cluster protocol channels.
- Rebuild from clean artifacts when upgrading codecs.
When it happens
Trigger: A fragment is polled on the consensus module subscription whose messageHeaderDecoder.schemaId() does not equal MessageHeaderDecoder.SCHEMA_ID, i.e. the remote peer (or a mixed-version node) sends cluster protocol messages encoded with a different aeron-cluster SBE schema.
Common situations: Cluster nodes running mismatched Aeron versions with regenerated SBE codecs; a custom service or rogue client publishing non-cluster messages onto the consensus module's subscription channel; stale build artifacts mixing codec jars.
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 cluster egress…
- expected schemaId= , actual=
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/3c0e0b7e62930ad0.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModuleAdapter.java:67
{
subscription.close();
}
int poll()
{
return subscription.controlledPoll(fragmentAssembler, FRAGMENT_LIMIT);
}
@SuppressWarnings("MethodLength")
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 ClusterException("expected schemaId=" + MessageHeaderDecoder.SCHEMA_ID + ", actual=" + schemaId);
}
ControlledFragmentHandler.Action action = ControlledFragmentHandler.Action.CONTINUE;
switch (messageHeaderDecoder.templateId())
{
case SessionMessageHeaderDecoder.TEMPLATE_ID:
sessionMessageHeaderDecoder.wrap(
buffer,
offset + MessageHeaderDecoder.ENCODED_LENGTH,
messageHeaderDecoder.blockLength(),
messageHeaderDecoder.version());
consensusModuleAgent.onServiceMessage(
sessionMessageHeaderDecoder.clusterSessionId(),
buffer,
offset + AeronCluster.SESSION_HEADER_LENGTH,
length - AeronCluster.SESSION_HEADER_LENGTH);View on GitHub (pinned to 6d60124e15)