apache/cassandra · error · MarshalException

Unexpected extraneous bytes after value

Error message

Unexpected %s extraneous bytes after %s value

What it means

VectorType throws this MarshalException when a serialized vector value contains more bytes than the declared dimension x element-size requires. Cassandra's vector marshaling requires the byte buffer to be fully consumed after reading all elements; leftover trailing bytes mean the value is malformed or was written by a different type definition.

Solutions

  1. Check the buffer length equals the exact expected size (dimension * element type size) before passing it to the vector type's validate/decompose methods
  2. Verify the vector column's dimension and element type in the schema match how the value was produced
  3. Re-write the affected data with the correct type; if data on disk is corrupted, run scrub or restore from backup
  4. If from user input, trim or reject values with trailing bytes at parse time

Example fix

// before
ByteBuffer value = ByteBuffer.allocate(20); // 5 floats written, but column is vector<float, 4>
VectorType.getInstance(FloatType.instance, 4).validate(value);
// after
if (value.remaining() != 4 * 4) throw new IllegalArgumentException("expected 16 bytes for vector<float,4>");
VectorType.getInstance(FloatType.instance, 4).validate(value);
Defensive patterns

Strategy: validation

Validate before calling

int expected = dimension * elementType.valueLengthIfFixed();
if (value == null || value.remaining() != expected) throw new IllegalArgumentException("expected " + expected + " bytes");

Try / catch

try { vectorType.validate(buffer); } catch (MarshalException e) { log.error("malformed vector value: {}", e.getMessage()); throw new IllegalArgumentException(e); }

Prevention

When it happens

Trigger: Calling VectorType.fromString / decompose / validate (via decomposeUn Type) on a buffer whose byte count exceeds dimension * elementLength, e.g. passing a value with extra trailing bytes, or validating a buffer typed as a vector with a smaller dimension than the data was written for.

Common situations: Schema changed a vector column's dimension or element type after data was written; manually constructed ByteBuffers for tests; corrupted SSTable or commit-log data; mixing up fixed-length element types (e.g. float vs double).

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/453d2cf12010b387. Report an issue: GitHub.

Appendix: source

Thrown at src/java/org/apache/cassandra/db/marshal/VectorType.java:381

    private void check(List<?> values)
    {
        if (values.size() != dimension)
            throw new MarshalException(String.format("Required %d elements, but saw %d", dimension, values.size()));

        // This code base always works with a list that is RandomAccess, so can use .get to avoid allocation
        for (int i = 0; i < dimension; i++)
        {
            Object value = values.get(i);
            if (value == null || (value instanceof ByteBuffer && elementSerializer.isNull((ByteBuffer) value)))
                throw new MarshalException(String.format("Element at index %d is null (expected type %s); given %s", i, elementType.asCQL3Type(), values));
        }
    }

    private <V> void checkConsumedFully(V buffer, ValueAccessor<V> accessor, int offset)
    {
        int remaining = accessor.sizeFromOffset(buffer, offset);
        if (remaining > 0)
            throw new MarshalException("Unexpected " + remaining + " extraneous bytes after " + asCQL3Type() + " value");
    }
    
    private static void rejectNullOrEmptyValue()
    {
        throw new MarshalException("Invalid empty vector value");
    }

    @Override
    public ByteBuffer getMaskedValue()
    {
        List<ByteBuffer> values = Collections.nCopies(dimension, elementType.getMaskedValue());
        return serializer.pack(values, ByteBufferAccessor.instance);
    }

    public abstract class VectorSerializer extends TypeSerializer<List<T>>
    {
        public abstract <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR);

View on GitHub (pinned to 88fd0f6a0e)