apache/cassandra · error · IOException

Expected exactly %d bytes, but was %d

Error message

Expected exactly %d bytes, but was %d

What it means

AbstractType.writeValue serializes a value to an output stream; when the caller supplies an expectedValueLength, the actual byte-buffer size must match exactly. A mismatch means the caller's recorded length disagrees with the real serialized size, so the write is aborted with this IOException.

Source

Thrown at src/java/org/apache/cassandra/db/marshal/AbstractType.java:587

    // This assumes that no empty values are passed
    public void writeValue(ByteBuffer value, DataOutputPlus out) throws IOException
    {
        writeValue(value, ByteBufferAccessor.instance, out);
    }

    // This assumes that no empty values are passed
    public  <V> void writeValue(V value, ValueAccessor<V> accessor, DataOutputPlus out) throws IOException
    {
        assert !isNull(value, accessor) : "bytes should not be null for type " + this;
        int expectedValueLength = valueLengthIfFixed;
        if (expectedValueLength >= 0)
        {
            int actualValueLength = accessor.size(value);
            if (actualValueLength == expectedValueLength)
                accessor.write(value, out);
            else
                throw new IOException(String.format("Expected exactly %d bytes, but was %d",
                                                    expectedValueLength, actualValueLength));
        }
        else
        {
            accessor.writeWithVIntLength(value, out);
        }
    }

    public  <V> void writeValue(IndexedValueHolder<V> valueHolder, int i, ValueAccessor<V> accessor, DataOutputPlus out) throws IOException
    {
        assert !valueHolder.isNull(i) : "bytes should not be null for type " + this;
        int expectedValueLength = valueLengthIfFixed;
        if (expectedValueLength >= 0)
        {
            int actualValueLength = valueHolder.size(i);
            if (actualValueLength == expectedValueLength)
                accessor.write(valueHolder, i, out);
            else

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Pass expectedValueLength = -1 so the value is written with its actual (VInt-encoded) length.
  2. Recompute the size with AbstractType.valueLength(value) / value.remaining() immediately before writing.
  3. Check for value mutation (slicing, duplicate, reuse of ByteBuffers) between size computation and write.

Example fix

// before
type.writeValue(value, out, staleSize);
// after
type.writeValue(value, out, value.remaining()); // or -1 to write actual length
Defensive patterns

Strategy: try-catch

Validate before calling

if (expectedValueLength >= 0 && value.remaining() != expectedValueLength) throw new IllegalStateException("length mismatch: " + value.remaining() + " != " + expectedValueLength);

Try / catch

catch (IOException e) { throw new StreamingException("value length mismatch while writing", e); }

Prevention

When it happens

Trigger: Calling writeValue (directly or via writeValueSkippingNullAndEmpty) with expectedValueLength >= 0 that differs from value.remaining()/size — e.g. a pre-computed serialized size from stale or corrupted metadata.

Common situations: Streaming/mutation-forwarding code paths where sizes were computed before mutation; custom compaction or repair tooling copying values with wrong length headers; deserialized value mutated after size was captured.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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