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);
elseView on GitHub (pinned to 88fd0f6a0e)
Solutions
- Pass expectedValueLength = -1 so the value is written with its actual (VInt-encoded) length.
- Recompute the size with AbstractType.valueLength(value) / value.remaining() immediately before writing.
- 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
- Pass -1 as expectedValueLength unless the length is freshly computed.
- Recompute value.remaining() immediately before writeValue.
- Avoid mutating ByteBuffers after capturing their size.
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
- Corrupted sstable. Invalid flags found deserializing Deletio
- EOF after <skipped> bytes out of <n>
- [Stream {}] Error while reading partition {} from stream on
- Serialized size must not be more than 2GiB
- Unable to allocate %s
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/3b3755cfd8f18485.
Report an issue: GitHub.