apache/cassandra · error · IllegalArgumentException

Hash of unexpected size when serializing a Leaf off-heap: "…

Error message

Hash of unexpected size when serializing a Leaf off-heap: " + hash.length

What it means

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.

Solutions

  1. Ensure leaf hashes are computed with the digest whose output equals HASH_SIZE
  2. Validate hash.length == MerkleTree.HASH_SIZE before constructing/serializing leaves
  3. Use MerkleTree's own hash consumers instead of injecting externally computed hashes
  4. Regenerate the tree if it came from an incompatible version

Example fix

// before
byte[] hash = md5.digest(data); // wrong digest length
OnHeapLeaf leaf = new OnHeapLeaf(hash);
// after
byte[] hash = HashingHasher.hash(data); // produces HASH_SIZE bytes
assert hash.length == MerkleTree.HASH_SIZE;
OnHeapLeaf leaf = new OnHeapLeaf(hash);
Defensive patterns

Strategy: validation

Validate before calling

// Validate before constructing/serializing a leaf
if (hash.length != MerkleTree.HASH_SIZE) {
    throw new IllegalArgumentException("Hash must be " + MerkleTree.HASH_SIZE + " bytes, got " + hash.length);
}
OnHeapLeaf leaf = new OnHeapLeaf(hash);
leaf.serializeOffHeap(buffer, partitioner);

Type guard

static boolean hasValidHashSize(byte[] hash) {
    return hash != null && hash.length == MerkleTree.HASH_SIZE;
}

Try / catch

try {
    leaf.serializeOffHeap(buffer, partitioner);
} catch (IllegalArgumentException e) {
    logger.error("Leaf hash size invalid: {}", e.getMessage());
    // recompute the hash with the expected digest and retry once
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/2d0df5b80259e0c1. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/utils/MerkleTree.java:1112

            {
                case HASH_SIZE:
                    byte[] hash = new byte[HASH_SIZE];
                    in.readFully(hash);
                    return new OnHeapLeaf(hash);
                case 0:
                    return new OnHeapLeaf();
                default:
                    throw new IllegalStateException(format("Hash of size %d encountered, expecting %d or %d", size, HASH_SIZE, 0));
            }
        }

        int serializeOffHeap(ByteBuffer buffer, IPartitioner p)
        {
            if (buffer.remaining() < OffHeapLeaf.maxOffHeapSize())
                throw new IllegalStateException("Insufficient remaining bytes to deserialize a Leaf node off-heap");

            if (hash.length != HASH_SIZE)
                throw new IllegalArgumentException("Hash of unexpected size when serializing a Leaf off-heap: " + hash.length);

            final int position = buffer.position();
            buffer.put(hash);
            return ~position;
        }

        @Override
        public String toString()
        {
            return "#<OnHeapLeaf " + Node.toString(hash()) + '>';
        }
    }

    static class OffHeapLeaf extends OffHeapNode implements Leaf
    {
        static final int HASH_BYTES_OFFSET = 0;

        OffHeapLeaf(ByteBuffer buffer, int offset)

View on GitHub (pinned to 88fd0f6a0e)