apache/cassandra · error · MarshalException

Unexpected extraneous bytes after set value

Error message

Unexpected extraneous bytes after set value

What it means

SetSerializer.validate decodes the declared number of elements and then checks that no bytes remain after the last element. Leftover bytes mean the buffer is longer than the encoded set it claims to hold, so the value is rejected as malformed. This keeps corrupt or wrongly-sized data from entering the database.

Source

Thrown at src/java/org/apache/cassandra/serializers/SetSerializer.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 set");
        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 set value");
        }
        catch (BufferUnderflowException | IndexOutOfBoundsException e)
        {
            throw new MarshalException("Not enough bytes to read a set");
        }
    }

    @Override
    public <V> Set<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 set");

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Re-serialize the set with SetSerializer.serialize instead of assembling bytes manually.
  2. Trim the buffer to the exact serialized length (duplicate + limit) before validating.
  3. Check the code path that produced the buffer for slicing/concatenation bugs.
  4. Catch MarshalException and treat the value as invalid/corrupt.

Example fix

// before
ByteBuffer padded = ByteBuffer.allocate(serialized.remaining() + 8);
padded.put(serialized);
setSerializer.validate(padded, ByteBufferAccessor.instance);
// after
setSerializer.validate(serialized.duplicate(), ByteBufferAccessor.instance);
Defensive patterns

Strategy: validation

Validate before calling

// Java
ByteBuffer dup = buf.duplicate();
setSerializer.validate(dup, ByteBufferAccessor.instance); // rejects trailing bytes

Try / catch

try {
    setSerializer.validate(buf.duplicate(), ByteBufferAccessor.instance);
} catch (MarshalException e) {
    log.warn("Set value malformed: {}", e.getMessage());
}

Prevention

When it happens

Trigger: Validating a buffer with trailing garbage, concatenating two serialized sets, or passing bytes whose size prefix undercounts the real element count relative to buffer length (e.g. buffer padded or holding another value appended).

Common situations: Manual byte-buffer slicing off-by-one errors; application code appending extra bytes; corrupt storage payload surfaced during validation; test harnesses building buffers by hand.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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