apache/cassandra · error · MarshalException

Not enough bytes to read size of %dth field %s

Error message

Not enough bytes to read size of %dth field %s

What it means

When converting a serialized UserType (UDT) value to a CQL literal, CQL3Type.toCQLLiteral reads a 4-byte size prefix for each declared field. If fewer than 4 bytes remain where the next field's size should be, the buffer is corrupt/truncated and MarshalException is thrown naming the field index and name.

Source

Thrown at src/java/org/apache/cassandra/cql3/CQL3Type.java:406

        @Override
        public String toCQLLiteral(ByteBuffer buffer)
        {
            if (buffer == null)
                return "null";


            StringBuilder target = new StringBuilder();
            buffer = buffer.duplicate();
            target.append('{');
            for (int i = 0; i < type.size(); i++)
            {
                // we allow the input to have less fields than declared so as to support field addition.
                if (!buffer.hasRemaining())
                    break;

                if (buffer.remaining() < 4)
                    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)));

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Verify the ByteBuffer contains a complete, uncorrupted serialized UDT value (check remaining() against the expected encoding)
  2. Re-read or re-fetch the value — the stored data may be truncated
  3. Use TypeSerializer/UTCMetaData-compliant serialization paths instead of hand-building byte buffers

Example fix

// before
String literal = udtType.asCQL3Type().toCQLLiteral(sliceOf(valueBuffer, 0, 6)); // truncated
// after
String literal = udtType.asCQL3Type().toCQLLiteral(valueBuffer.duplicate()); // full value
Defensive patterns

Strategy: try-catch

Validate before calling

if (buffer == null || buffer.remaining() < 4) throw new MarshalException("Buffer too small for UDT field");

Try / catch

try { String lit = udtType.asCQL3Type().toCQLLiteral(buffer); } catch (MarshalException e) { log.error("Corrupt UDT value: {}", e.getMessage(), e); }

Prevention

When it happens

Trigger: Passing a truncated or manually corrupted ByteBuffer to toCQLLiteral for a UDT type; deserializing a value written by a different/broken serializer; off-by-one slicing of a serialized blob.

Common situations: Application code storing UDT blobs and re-rendering them after partial reads; data corruption on disk or in transit; protocol mismatches when bytes were hand-assembled.

Related errors


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