aeron-io/aeron · error · ClusterException
expected schemaId= , actual=
Error message
expected schemaId=${MessageHeaderDecoder.SCHEMA_ID}, actual=${schemaId} What it means
ClusterControlAdapter.onFragment wraps each incoming buffer with an SBE MessageHeaderDecoder and verifies the schemaId matches MessageHeaderDecoder.SCHEMA_ID. A mismatch means the fragment is not an Aeron cluster control SBE message of the expected schema, so decoding cannot proceed safely.
Solutions
- Ensure all cluster members and clients use the same Aeron version/schema
- Stop unrelated publishers from sending on the control channel
- Verify channel/endpoint configuration separates control traffic from other traffic
- Regenerate/rebuild any custom codecs from the matching aeron-cluster schema
Example fix
// before // member on aeron 1.40 talking to member on 1.44 with changed schema // after // align versions: <dependency> <groupId>io.aeron</groupId> <artifactId>aeron-all</artifactId> <version>1.44.1</version> </dependency>
Defensive patterns
Strategy: try-catch
Validate before calling
// verify peer version compatibility before subscribing to control channel // keep aeron-all versions identical across all cluster nodes
Try / catch
try {
controlAdapter.onFragment(buffer, offset, length, header);
} catch (ClusterException e) {
if (e.getMessage().contains("expected schemaId")) {
log.error("schema/version mismatch on control channel; check Aeron versions", e);
}
} Prevention
- Pin a single aeron-all version across the deployment
- Never publish non-cluster SBE messages on control channels
- Log the offending schemaId to identify the mismatching producer
When it happens
Trigger: A message arrives on the control-toggle/control-response subscription whose SBE schemaId differs from the cluster-codec schema (e.g. messages from a different schema version or unrelated publisher on the same channel).
Common situations: Mixed Aeron versions between cluster members (schema changed between releases), accidentally pointing multiple components at the same control channel, or garbage/corrupt frames on the 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=<MessageHeaderDecoder.SCHEMA_ID>, 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/0bece49ba2cc234c.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-cluster/src/main/java/io/aeron/cluster/ClusterControlAdapter.java:82
int poll()
{
return subscription.poll(fragmentAssembler, 1);
}
boolean isBound()
{
return subscription.isConnected();
}
@SuppressWarnings("MethodLength")
private 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);
}
final int templateId = messageHeaderDecoder.templateId();
if (templateId == ClusterMembersResponseDecoder.TEMPLATE_ID)
{
clusterMembersResponseDecoder.wrap(
buffer,
offset + MessageHeaderDecoder.ENCODED_LENGTH,
messageHeaderDecoder.blockLength(),
messageHeaderDecoder.version());
final long correlationId = clusterMembersResponseDecoder.correlationId();
final int leaderMemberId = clusterMembersResponseDecoder.leaderMemberId();
final String activeMembers = clusterMembersResponseDecoder.activeMembers();
clusterMembersResponseDecoder.skipPassiveFollowers();
listener.onClusterMembersResponse(correlationId, leaderMemberId, activeMembers);
}View on GitHub (pinned to 6d60124e15)