apache/cassandra · error · MarshalException
Not enough bytes to read %dth
Error message
Not enough bytes to read %dth %s
What it means
TupleType.unpack walks a serialized tuple value, reading a 4-byte length prefix before each component. If the buffer ends before a complete length prefix can be read, it throws this MarshalException identifying which component index could not be read — the serialized value is truncated or corrupt.
Solutions
- Verify the buffer length and that the value was serialized by the same TupleType being used to unpack it.
- Use the TupleType builder / valueType APIs instead of hand-assembling bytes.
- Re-read the source data (or repair the table) if the underlying value is truncated; validate with type.validate() before unpacking.
Example fix
// before
ByteBuffer tuple = ByteBuffer.wrap(new byte[]{0,0,0,5,'h','e','l','l'}); // truncated
List<ByteBuffer> parts = tupleType.split(tuple);
// after
if (tuple.remaining() < expectedSize)
throw new IOException("truncated tuple value");
List<ByteBuffer> parts = tupleType.split(tuple); Defensive patterns
Strategy: try-catch
Validate before calling
if (value == null || value.remaining() < 4) throw new IllegalArgumentException("tuple value too short"); Try / catch
try { List<ByteBuffer> parts = tupleType.split(value); } catch (MarshalException e) { /* log corrupted value, e.getMessage(), skip/repair */ } Prevention
- Always build tuple values with TupleType builders, not manual byte assembly
- Ensure the unpacking TupleType matches the one used at write time
- Validate values with TupleType.validate() before unpacking; treat failures as data corruption and log for repair
When it happens
Trigger: Decomposing a ByteBuffer into tuple components (TupleType.elements/components/bufs/buildAndSplit) where the buffer is shorter than the serialized tuple — e.g. truncated storage, wrong byte offsets, or a hand-built buffer missing bytes.
Common situations: Manually concatenating component bytes without proper length prefixes; reading a column value with the wrong TupleType (fewer/shorter encoding); corrupted SSTable data or a slicing bug copying a partial buffer.
Understand the failure class
Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.
Related errors
- Not enough bytes to read %dth component
- Not enough bytes to read size of %dth component
- EmptyType only accept empty values
- Expected 0 or at least 4 bytes
- Expected 2 bytes for a smallint
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/27bb533cf5fd8660.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/db/marshal/TupleType.java:316
return pack(accessor, Arrays.asList(componentBuffers));
}
@Override
public <V> List<V> unpack(V value, ValueAccessor<V> accessor)
{
int numberOfElements = size();
List<V> components = new ArrayList<>(numberOfElements);
int length = accessor.size(value);
int position = 0;
for (int i = 0; i < numberOfElements; i++)
{
if (position == length)
{
return components;
}
if (position + 4 > length)
throw new MarshalException(String.format("Not enough bytes to read %dth %s", i, componentOrFieldName(i)));
int size = accessor.getInt(value, position);
position += 4;
// size < 0 means null value
if (size >= 0)
{
if (length - position < size)
throw new MarshalException(String.format("Not enough bytes to read %dth %s", i, componentOrFieldName(i)));
components.add(accessor.slice(value, position, size));
position += size;
}
else
components.add(null);
}
// error out if we got more values in the tuple/UDT than we expectedView on GitHub (pinned to 88fd0f6a0e)