{"record":{"id":"2d0df5b80259e0c1","repo":"apache/cassandra","slug":"hash-of-unexpected-size-when-serializing-a-leaf-of","errorCode":null,"errorMessage":"Hash of unexpected size when serializing a Leaf off-heap: \" + hash.length","messagePattern":"Hash of unexpected size when serializing a Leaf off-heap: \" \\+ hash\\.length","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/utils/MerkleTree.java","lineNumber":1112,"sourceCode":"            {\n                case HASH_SIZE:\n                    byte[] hash = new byte[HASH_SIZE];\n                    in.readFully(hash);\n                    return new OnHeapLeaf(hash);\n                case 0:\n                    return new OnHeapLeaf();\n                default:\n                    throw new IllegalStateException(format(\"Hash of size %d encountered, expecting %d or %d\", size, HASH_SIZE, 0));\n            }\n        }\n\n        int serializeOffHeap(ByteBuffer buffer, IPartitioner p)\n        {\n            if (buffer.remaining() < OffHeapLeaf.maxOffHeapSize())\n                throw new IllegalStateException(\"Insufficient remaining bytes to deserialize a Leaf node off-heap\");\n\n            if (hash.length != HASH_SIZE)\n                throw new IllegalArgumentException(\"Hash of unexpected size when serializing a Leaf off-heap: \" + hash.length);\n\n            final int position = buffer.position();\n            buffer.put(hash);\n            return ~position;\n        }\n\n        @Override\n        public String toString()\n        {\n            return \"#<OnHeapLeaf \" + Node.toString(hash()) + '>';\n        }\n    }\n\n    static class OffHeapLeaf extends OffHeapNode implements Leaf\n    {\n        static final int HASH_BYTES_OFFSET = 0;\n\n        OffHeapLeaf(ByteBuffer buffer, int offset)","sourceCodeStart":1094,"sourceCodeEnd":1130,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/utils/MerkleTree.java#L1094-L1130","documentation":"OffHeapLeaf serialization requires the leaf's hash array to be exactly HASH_SIZE long (or the leaf to be empty); any other length throws IllegalArgumentException('Hash of unexpected size when serializing a Leaf off-heap: ...'). This enforces the fixed wire layout of off-heap leaves.","triggerScenarios":"Constructing an OnHeapLeaf/leaf with a hash byte[] whose length differs from MerkleTree.HASH_SIZE (e.g., hashes computed with a different digest) and then serializing it off-heap.","commonSituations":"Custom code computing leaf hashes with a non-default digest length; trees produced by a different Cassandra version with a different hash algorithm; hand-built leaves in tests.","solutions":["Ensure leaf hashes are computed with the digest whose output equals HASH_SIZE","Validate hash.length == MerkleTree.HASH_SIZE before constructing/serializing leaves","Use MerkleTree's own hash consumers instead of injecting externally computed hashes","Regenerate the tree if it came from an incompatible version"],"exampleFix":"// before\nbyte[] hash = md5.digest(data); // wrong digest length\nOnHeapLeaf leaf = new OnHeapLeaf(hash);\n// after\nbyte[] hash = HashingHasher.hash(data); // produces HASH_SIZE bytes\nassert hash.length == MerkleTree.HASH_SIZE;\nOnHeapLeaf leaf = new OnHeapLeaf(hash);","handlingStrategy":"validation","validationCode":"// Validate before constructing/serializing a leaf\nif (hash.length != MerkleTree.HASH_SIZE) {\n    throw new IllegalArgumentException(\"Hash must be \" + MerkleTree.HASH_SIZE + \" bytes, got \" + hash.length);\n}\nOnHeapLeaf leaf = new OnHeapLeaf(hash);\nleaf.serializeOffHeap(buffer, partitioner);","typeGuard":"static boolean hasValidHashSize(byte[] hash) {\n    return hash != null && hash.length == MerkleTree.HASH_SIZE;\n}","tryCatchPattern":"try {\n    leaf.serializeOffHeap(buffer, partitioner);\n} catch (IllegalArgumentException e) {\n    logger.error(\"Leaf hash size invalid: {}\", e.getMessage());\n    // recompute the hash with the expected digest and retry once\n}","preventionTips":["Compute leaf hashes only with the digest matching HASH_SIZE","Never inject hashes produced by other algorithms or versions","Add an assert on hash.length in test helpers that build trees","Regenerate trees after upgrading if the hash algorithm changed"],"tags":["merkle-tree","hash","off-heap"],"backgroundTag":"invalid-argument-value","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"}