{"record":{"id":"e9e3e34e7134e13e","repo":"apache/cassandra","slug":"unexpected-node-type-ident","errorCode":null,"errorMessage":"Unexpected node type: \" + ident","messagePattern":"Unexpected node type: \" \\+ ident","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/utils/MerkleTree.java","lineNumber":923,"sourceCode":"\n        @Override\n        public long partitionsInRange()\n        {\n            return partitionsInRange;\n        }\n\n        static OnHeapNode deserialize(DataInputPlus in, IPartitioner p, int version) throws IOException\n        {\n            byte ident = in.readByte();\n\n            switch (ident)\n            {\n                case Inner.IDENT:\n                    return OnHeapInner.deserializeWithoutIdent(in, p, version);\n                case Leaf.IDENT:\n                    return OnHeapLeaf.deserializeWithoutIdent(in);\n                default:\n                    throw new IOException(\"Unexpected node type: \" + ident);\n            }\n        }\n\n        abstract int serializeOffHeap(ByteBuffer buffer, IPartitioner p) throws IOException;\n    }\n\n    static abstract class OffHeapNode implements Node\n    {\n        protected final ByteBuffer buffer;\n        protected final int offset;\n\n        OffHeapNode(ByteBuffer buffer, int offset)\n        {\n            this.buffer = buffer;\n            this.offset = offset;\n        }\n\n        ByteBuffer buffer()","sourceCodeStart":905,"sourceCodeEnd":941,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/utils/MerkleTree.java#L905-L941","documentation":"MerkleTree's on-heap node deserializer reads an IDENT byte to decide which node class (Inner or Leaf) to construct. Any other byte means the serialized tree is unreadable, so it throws IOException('Unexpected node type: ' + ident). This protects against version skew or corruption in MerkleTree streams exchanged during repair.","triggerScenarios":"Streaming/deserializing a MerkleTree whose bytes contain a node IDENT not matching Inner.IDENT or Leaf.IDENT — typically a tree serialized by a different Cassandra version or corrupted stream data.","commonSituations":"Repair between nodes on incompatible Cassandra versions; corrupted network payloads during anti-entropy sync; deserializing an old serialized tree dump with newer code.","solutions":["Ensure all nodes doing repair run compatible Cassandra versions","Regenerate the MerkleTrees (rerun repair validation) instead of reusing the serialized payload","Hex-dump the stream to check for truncation or corruption upstream","Confirm the deserializer version parameter matches the version used at serialization"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try (DataInputStream in = new DataInputStream(stream)) {\n    MerkleTree tree = MerkleTree.deserialize(in, version);\n} catch (IOException e) {\n    if (e.getMessage().startsWith(\"Unexpected node type\")) {\n        logger.error(\"MerkleTree stream corrupted or version-mismatched: {}\", e.getMessage());\n        // trigger re-validation / full repair instead of trusting the tree\n    }\n    throw e;\n}","preventionTips":["Keep Cassandra versions uniform across repair participants","Never reuse serialized trees across versions; regenerate via repair","Checksum tree payloads when persisting or streaming them","Treat this as corruption: re-validate rather than retrying the same bytes"],"tags":["serialization","repair","merkle-tree"],"backgroundTag":"unexpected-response-shape","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}