aeron-io/aeron · error · ClusterException
expected schemaId= , actual=
Error message
expected schemaId=${MessageHeaderDecoder.SCHEMA_ID}, actual=${schemaId} What it means
ConsensusAdapter.onFragment wraps each incoming buffer with MessageHeaderDecoder and verifies the SBE block schemaId matches the cluster protocol's expected SCHEMA_ID; a mismatch throws ClusterException. This means a message arrived on the consensus transport that is not a valid cluster-protocol SBE message.
Solutions
- Verify all cluster members run the same Aeron version so their SBE schemas match.
- Check aeron.cluster.channels / consensus channel and streamId configuration for collisions with other applications.
- Ensure no other publisher is sending on the consensus channel/streamId.
- If connecting clusters together, use distinct channels or an egress/ingest boundary rather than sharing the consensus stream.
Example fix
// before // node A: -Daeron.cluster.consensus.channel=aeron:udp?endpoint=host:9010 (shared with another app sending SBE with different schema) // after: dedicate the stream/channel to the cluster -Daeron.cluster.consensus.channel=aeron:udp?endpoint=host:9020 -Daeron.cluster.consensus.streamId=101
Defensive patterns
Strategy: validation
Validate before calling
// before joining a cluster, verify config consistency
if (!consensusChannel.equals(expectedConsensusChannel) || consensusStreamId != expectedStreamId)
{
throw new IllegalStateException("consensus channel/streamId mismatch with cluster config");
} Try / catch
try
{
consensusModule.start();
}
catch (ClusterException ex)
{
if (ex.getMessage().contains("expected schemaId"))
{
// wrong sender or Aeron version on the consensus channel
}
else throw ex;
} Prevention
- Pin the same Aeron version on all cluster members.
- Never share the consensus channel/streamId with other applications or clusters.
- Audit publishers on the consensus endpoint if the error appears intermittently.
When it happens
Trigger: Receiving a fragment on the cluster consensus channel whose SBE header schemaId differs from MessageHeaderDecoder.SCHEMA_ID (e.g. messages from another Aeron/SBE protocol version or a different application sharing the channel/stream).
Common situations: Two Aeron versions or applications configured to use the same channel/stream: one speaks a different SBE schema; misconfigured consensus channel overlapping with another cluster's streamId; corrupted messages from a misbehaving publisher.
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=
- unexpected response: code=
- unknown RES_TYPE=
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/07eda86d296c41d2.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-cluster/src/main/java/io/aeron/cluster/ConsensusAdapter.java:87
public int poll()
{
return subscription.poll(fragmentAssembler, FRAGMENT_LIMIT);
}
public int poll(final int limit)
{
return subscription.poll(fragmentAssembler, limit);
}
@SuppressWarnings("MethodLength")
public void 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);
}
switch (messageHeaderDecoder.templateId())
{
case CanvassPositionDecoder.TEMPLATE_ID:
canvassPositionDecoder.wrap(
buffer,
offset + MessageHeaderDecoder.ENCODED_LENGTH,
messageHeaderDecoder.blockLength(),
messageHeaderDecoder.version());
consensusModuleAgent.onCanvassPosition(
canvassPositionDecoder.logLeadershipTermId(),
canvassPositionDecoder.logPosition(),
canvassPositionDecoder.leadershipTermId(),
canvassPositionDecoder.followerMemberId(),
canvassPositionDecoder.protocolVersion());
break;View on GitHub (pinned to 6d60124e15)