apache/cassandra · error · MarshalException

Unexpected extraneous bytes after list value

Error message

Unexpected extraneous bytes after list value

What it means

After reading the declared number of list elements, ListSerializer.validate() checks that no bytes remain between the current offset and the end of the buffer. Leftover trailing bytes mean the buffer is longer than the encoded list it claims to contain, so the data is corrupt or mis-framed. This catches buffers that concatenate a list with unrelated extra data.

Source

Thrown at src/java/org/apache/cassandra/serializers/ListSerializer.java:86

    @Override
    public <V> void validate(V input, ValueAccessor<V> accessor)
    {
        if (accessor.isEmpty(input))
            throw new MarshalException("Not enough bytes to read a list");
        try
        {
            int n = readCollectionSize(input, accessor);
            int offset = sizeOfCollectionSize();
            for (int i = 0; i < n; i++)
            {
                V value = readNonNullValue(input, accessor, offset);
                offset += sizeOfValue(value, accessor);
                elements.validate(value, accessor);
            }

            if (!accessor.isEmptyFromOffset(input, offset))
                throw new MarshalException("Unexpected extraneous bytes after list value");
        }
        catch (BufferUnderflowException | IndexOutOfBoundsException e)
        {
            throw new MarshalException("Not enough bytes to read a list");
        }
    }

    @Override
    public <V> List<T> deserialize(V input, ValueAccessor<V> accessor)
    {
        try
        {
            int n = readCollectionSize(input, accessor);
            int offset = sizeOfCollectionSize();

            if (n < 0)
                throw new MarshalException("The data cannot be deserialized as a list");

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Regenerate the serialized list with the official ListSerializer instead of hand-built buffers.
  2. Inspect the source of the buffer (ETL job, migration tool) for extra padding or appended fields and strip them.
  3. Check for double-wrapping: a ByteBuffer serialized inside another collection framing.
  4. If data at rest is corrupt, run a repair/scrub to rewrite the affected rows.

Example fix

// before
ByteBuffer bad = ByteBuffer.allocate(4 + 4).putInt(0).putInt(42); // count + trailing int
// after
List<Integer> l = Collections.singletonList(42);
ByteBuffer good = ListSerializer.instance.serialize(l, Int32Type.instance, ByteBufferUtil.NONE); // use proper serializer
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-validate framing: expected bytes = 4 + sum(element sizes); if (blob.remaining() != expected) reject before validate()

Try / catch

try { listSerializer.validate(blob, ByteBufferUtil.NONE); } catch (org.apache.cassandra.exceptions.MarshalException e) { log.error("list blob misframed: {}", e.getMessage()); blob = reSerializeFromSource(); }

Prevention

When it happens

Trigger: Calling ListSerializer.validate(input, accessor) where n elements read successfully but accessor.isEmptyFromOffset(input, offset) is false — i.e. extra bytes remain after the last element.

Common situations: Manual byte-concatenation of a list with a delimiter or padding; sending a frozen<list> blob that embeds extra fields; truncated/corrupt SSTable or hint data being re-validated; off-by-one errors in hand-rolled collection serialization.

Related errors


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