apache/cassandra · error · MarshalException
Not enough bytes to read %dth field %s
Error message
Not enough bytes to read %dth field %s
What it means
While rendering a UDT value as a CQL literal, after reading a field's 4-byte size the code requires that many bytes to actually contain the field value. If the buffer ends early, the payload is truncated and MarshalException is thrown naming the field index and name.
Source
Thrown at src/java/org/apache/cassandra/cql3/CQL3Type.java:424
throw new MarshalException(String.format("Not enough bytes to read size of %dth field %s", i, type.fieldName(i)));
int size = buffer.getInt();
if (i > 0)
target.append(", ");
target.append(ColumnIdentifier.maybeQuote(type.fieldNameAsString(i)));
target.append(": ");
// size < 0 means null value
if (size < 0)
{
target.append("null");
continue;
}
if (buffer.remaining() < size)
throw new MarshalException(String.format("Not enough bytes to read %dth field %s", i, type.fieldName(i)));
ByteBuffer field = ByteBufferUtil.readBytes(buffer, size);
target.append(type.fieldType(i).asCQL3Type().toCQLLiteral(field));
}
target.append('}');
return target.toString();
}
@Override
public final boolean equals(Object o)
{
if(!(o instanceof UserDefined))
return false;
UserDefined that = (UserDefined)o;
return type.equals(that.type);
}
View on GitHub (pinned to 88fd0f6a0e)
Solutions
- Ensure the serialized UDT value is complete: each field must carry its full size-prefixed payload
- Re-produce the value via the official UserType serializer instead of manual byte assembly
- Catch MarshalException and log/handle the corrupt value rather than crashing
Example fix
// before ByteBuffer bad = ByteBuffer.allocate(4); bad.putInt(16); // claims 16 bytes, none follow String lit = udt.asCQL3Type().toCQLLiteral(bad); // after ByteBuffer good = userType.serializer().serialize(udtValue); String lit = udt.asCQL3Type().toCQLLiteral(good);
Defensive patterns
Strategy: try-catch
Validate before calling
ByteBuffer dup = buffer.duplicate(); // walk size prefixes
while (dup.hasRemaining()) { if (dup.remaining() < 4) throw new MarshalException("truncated"); int size = dup.getInt(); if (dup.remaining() < size) throw new MarshalException("field truncated"); dup.position(dup.position() + size); } Try / catch
try { String lit = udtType.asCQL3Type().toCQLLiteral(buffer); } catch (MarshalException e) { handleCorruptValue(e); } Prevention
- Serialize UDTs only via UserType/TupleType APIs
- Never slice serialized values at arbitrary offsets
- Detect and quarantine corrupt cells instead of rendering them
When it happens
Trigger: A field size prefix says e.g. 16 bytes but only 5 remain in the ByteBuffer; passing a buffer that was sliced mid-field; corrupted serialized UDT data.
Common situations: Byte buffers truncated by custom transport or storage layers; application code miscounting serialized field lengths when composing UDT bytes manually.
Related errors
- Not enough bytes to read size of %dth field %s
- Not enough bytes to read size of %dth component
- Not enough bytes to read %dth component
- Invalid operation (%s) for non-UDT column %s
- Invalid operation (%s) for frozen UDT column %s
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/edbe9fb2e8390aea.
Report an issue: GitHub.