{"record":{"id":"d573e38c1e885d26","repo":"aeron-io/aeron","slug":"expected-schemaid-schema-id-actual-schemaid-d573e3","errorCode":null,"errorMessage":"expected schemaId=<SCHEMA_ID>, actual=<schemaId>","messagePattern":"expected schemaId=<SCHEMA_ID>, actual=<schemaId>","errorType":"exception","errorClass":"ClusterException","httpStatus":null,"severity":"critical","filePath":"aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModuleAgent.java","lineNumber":1536,"sourceCode":"        final Header header)\n    {\n        if (null != consensusModuleExtension)\n        {\n            final int remainingMessageOffset = offset + MessageHeaderDecoder.ENCODED_LENGTH;\n            final int remainingMessageLength = length - MessageHeaderDecoder.ENCODED_LENGTH;\n\n            return consensusModuleExtension.onLogExtensionMessage(\n                actingBlockLength,\n                templateId,\n                schemaId,\n                actingVersion,\n                buffer,\n                remainingMessageOffset,\n                remainingMessageLength,\n                header);\n        }\n\n        throw new ClusterException(\"expected schemaId=\" + MessageHeaderDecoder.SCHEMA_ID + \", actual=\" + schemaId);\n    }\n\n    void onReplayTimerEvent(final long correlationId)\n    {\n        if (!timerService.cancelTimerByCorrelationId(correlationId))\n        {\n            expiredTimerCountByCorrelationIdMap.getAndIncrement(correlationId);\n        }\n    }\n\n    void onReplaySessionOpen(\n        final long logPosition,\n        final long correlationId,\n        final long clusterSessionId,\n        final long timestamp,\n        final int responseStreamId,\n        final String responseChannel)\n    {","sourceCodeStart":1518,"sourceCodeEnd":1554,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModuleAgent.java#L1518-L1554","documentation":"In ConsensusModuleAgent's replay/fragment handling, after dispatching to message decoders the agent verifies the SBE header schema id matched MessageHeaderDecoder.SCHEMA_ID; otherwise it throws. This protects log replay from decoding messages written with a different cluster protocol schema.","triggerScenarios":"During log or snapshot replay, a fragment's messageHeaderDecoder.schemaId() is not MessageHeaderDecoder.SCHEMA_ID, so none of the decoder branches handle it and the fallback throw is reached.","commonSituations":"Replaying a log produced by a different Aeron version with a changed cluster SBE schema; mixed-version cluster membership; corrupt log buffer contents from an external writer on the log channel.","solutions":["Ensure all cluster nodes run the same Aeron version so log schema ids are identical.","Verify nothing external is publishing to the cluster log channel.","Rebuild the cluster from a snapshot/archives produced with the current schema version.","Clean the classpath of duplicate/old aeron-cluster codec artifacts."],"exampleFix":"// before: node upgraded alone, log schema differs\n// after: stop all nodes, snapshot, upgrade every node, restart","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { cluster.start(); } catch (ClusterException e) { if (e.getMessage().contains(\"expected schemaId\")) { rebuildFromSnapshotWithCurrentSchema(); } else { throw e; } }","preventionTips":["Upgrade all nodes together after taking a snapshot.","Keep the log channel private to the cluster.","Avoid mixing codec artifacts from different Aeron releases."],"tags":["sbe","schema-mismatch","replay","cluster"],"backgroundTag":"schema-validation-failed","analyzedSha":"6d60124e15e35c11b49ba2e3c2c2858a09a18803","analyzedAt":"2026-09-12T11:17:07.683Z","contentChangedAt":"2026-09-12T11:17:07.683Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}