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

  1. Ensure the serialized UDT value is complete: each field must carry its full size-prefixed payload
  2. Re-produce the value via the official UserType serializer instead of manual byte assembly
  3. 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

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


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