{"record":{"id":"840c030c0fbe5af4","repo":"apache/cassandra","slug":"hash-of-unexpected-size-when-deserializing-an-off","errorCode":null,"errorMessage":"Hash of unexpected size when deserializing an off-heap Leaf node: \" + hashLength","messagePattern":"Hash of unexpected size when deserializing an off-heap Leaf node: \" \\+ hashLength","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/utils/MerkleTree.java","lineNumber":1151,"sourceCode":"        }\n\n        public int hashBytesOffset()\n        {\n            return offset + HASH_BYTES_OFFSET;\n        }\n\n        static int deserializeWithoutIdent(DataInput in, ByteBuffer buffer) throws IOException\n        {\n            if (buffer.remaining() < maxOffHeapSize())\n                throw new IllegalStateException(\"Insufficient remaining bytes to deserialize a Leaf node off-heap\");\n\n            final int position = buffer.position();\n\n            int hashLength = in.readByte();\n            if (hashLength > 0)\n            {\n                if (hashLength != HASH_SIZE)\n                    throw new IllegalStateException(\"Hash of unexpected size when deserializing an off-heap Leaf node: \" + hashLength);\n\n                byte[] hashBytes = getTempArray(HASH_SIZE);\n                in.readFully(hashBytes, 0, HASH_SIZE);\n                buffer.put(hashBytes, 0, HASH_SIZE);\n            }\n            else\n            {\n                buffer.put(EMPTY_HASH, 0, HASH_SIZE);\n            }\n\n            return ~position;\n        }\n\n        static int maxOffHeapSize()\n        {\n            return HASH_SIZE;\n        }\n","sourceCodeStart":1133,"sourceCodeEnd":1169,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/utils/MerkleTree.java#L1133-L1169","documentation":"OffHeapLeaf.deserializeWithoutIdent reads a hash length byte; a non-zero length must equal HASH_SIZE, otherwise it throws IllegalStateException('Hash of unexpected size when deserializing an off-heap Leaf node: ...'). The off-heap leaf layout stores either 0 (empty) or exactly HASH_SIZE hash bytes.","triggerScenarios":"Deserializing an off-heap leaf whose stored hash-length byte is neither 0 nor HASH_SIZE — data written by an incompatible Cassandra version (different hash size), stream corruption, or misaligned reads.","commonSituations":"Repair across mixed versions where digest output size changed; corrupted MerkleTree payloads in flight or at rest; reading at a wrong offset so an arbitrary byte is interpreted as the length.","solutions":["Confirm all repair participants run versions with the same HASH_SIZE","Regenerate the tree via a fresh repair validation","Check for stream truncation/offset desync before the leaf read","Inspect the reported hashLength to distinguish corruption from version skew"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    OffHeapLeaf.deserializeWithoutIdent(in, buffer);\n} catch (IllegalStateException e) {\n    if (e.getMessage().startsWith(\"Hash of unexpected size\")) {\n        logger.error(\"Corrupt or version-mismatched off-heap leaf: {}\", e.getMessage());\n        // discard the tree and re-run repair validation\n    }\n    throw e;\n}","preventionTips":["Keep identical Cassandra versions on all repair participants","Never deserialize trees written by other versions; regenerate instead","Checksum tree streams to detect corruption before parsing","Avoid manual parsing that could leave the stream misaligned at a length byte"],"tags":["merkle-tree","deserialization","off-heap","hash"],"backgroundTag":"internal-invariant-violation","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}