{"record":{"id":"a63f682828ef48f6","repo":"aeron-io/aeron","slug":"expected-schemaid-expected-actual-actual","errorCode":null,"errorMessage":"expected schemaId=${expected}, actual=${actual}","messagePattern":"expected schemaId=(.+?), actual=(.+?)","errorType":"exception","errorClass":"ClusterException","httpStatus":null,"severity":"error","filePath":"aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModuleSnapshotAdapter.java","lineNumber":72,"sourceCode":"    boolean isDone()\n    {\n        return isDone;\n    }\n\n    int poll()\n    {\n        return image.controlledPoll(fragmentAssembler, FRAGMENT_LIMIT);\n    }\n\n    @SuppressWarnings(\"MethodLength\")\n    public Action onFragment(final DirectBuffer buffer, final int offset, final int length, final Header header)\n    {\n        messageHeaderDecoder.wrap(buffer, offset);\n\n        final int schemaId = messageHeaderDecoder.schemaId();\n        if (MessageHeaderDecoder.SCHEMA_ID != schemaId)\n        {\n            throw new ClusterException(\"expected schemaId=\" + MessageHeaderDecoder.SCHEMA_ID + \", actual=\" + schemaId);\n        }\n\n        switch (messageHeaderDecoder.templateId())\n        {\n            case SessionMessageHeaderDecoder.TEMPLATE_ID:\n                sessionMessageHeaderDecoder.wrap(\n                    buffer,\n                    offset + MessageHeaderDecoder.ENCODED_LENGTH,\n                    messageHeaderDecoder.blockLength(),\n                    messageHeaderDecoder.version());\n\n                listener.onLoadPendingMessage(sessionMessageHeaderDecoder.clusterSessionId(), buffer, offset, length);\n                break;\n\n            case SnapshotMarkerDecoder.TEMPLATE_ID:\n                snapshotMarkerDecoder.wrap(\n                    buffer,\n                    offset + MessageHeaderDecoder.ENCODED_LENGTH,","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-cluster/src/main/java/io/aeron/cluster/ConsensusModuleSnapshotAdapter.java#L54-L90","documentation":"ConsensusModuleSnapshotAdapter.onFragment validates the SBE schema id on every snapshot fragment before decoding. The snapshot stream was produced with a different message schema than the one this binary was compiled against, so decoding is aborted with a ClusterException rather than misinterpreting bytes.","triggerScenarios":"Loading a cluster snapshot recording made by an older/newer Aeron version (or with a different generated SBE schema) than the ConsensusModule doing the replay; the header schemaId read from the buffer does not equal MessageHeaderDecoder.SCHEMA_ID.","commonSituations":"Rolling cluster upgrade/downgrade where nodes have mismatched Aeron versions; restoring a snapshot from an old archive after upgrading the cluster module; mixing snapshots taken with a custom-built SBE schema.","solutions":["Ensure all cluster nodes run the exact same Aeron version so generated codecs share one schema id","Start the cluster from a snapshot produced by the same binary version, or take a fresh snapshot after upgrading","If a protocol upgrade is required, follow Aeron's cluster migration procedure (backup, replay to a common version, re-snapshot)","Regenerate SBE codecs only from the schema version that matches the recorded data"],"exampleFix":"// before: replaying a snapshot recorded by an older Aeron version after upgrading the node\nClusterException: expected schemaId=101, actual=99\n// after: re-snapshot with the matching version, or pin the cluster to one Aeron version across all members\nmvn dependency:get -Dartifact=io.aeron:aeron-all:<same-version-on-all-nodes>","handlingStrategy":"try-catch","validationCode":"// Verify snapshot provenance before loading: same Aeron version and same cluster dir\nString aeronVersion = AeronVersion.VERSION;\n// compare with the version that wrote the snapshot recording (stored in appVersion via onLoadBeginSnapshot)","typeGuard":"boolean isCompatibleSchema(int schemaId) { return MessageHeaderDecoder.SCHEMA_ID == schemaId; }","tryCatchPattern":"try {\n    snapshotPlayer.load(...);\n} catch (ClusterException e) {\n    if (e.getMessage().startsWith(\"expected schemaId=\")) {\n        throw new IllegalStateException(\"Snapshot schema mismatch — restore a snapshot from the same Aeron version\", e);\n    }\n    throw e;\n}","preventionTips":["Pin all cluster members to the same Aeron version (test in CI)","Take a fresh snapshot immediately after upgrades before relying on restores","Keep backups of both the snapshot and the binary version that produced it"],"tags":["aeron","cluster","snapshot","sbe","schema-mismatch"],"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-15T23:17:13.987Z"}