apache/cassandra · error · MarshalException

Not enough bytes to header of the comparator part of compone

Error message

Not enough bytes to header of the comparator part of component %s

What it means

DynamicCompositeType.validateComparator() decodes each component of a dynamic composite value: the first 2 bytes are a header short that encodes either a byte length of a comparator class name or an alias bit. If fewer than 2 bytes remain at the current offset, the buffer is truncated/corrupt and this MarshalException is thrown during validation. It indicates malformed serialized composite data rather than a user-facing value problem.

Source

Thrown at src/java/org/apache/cassandra/db/marshal/DynamicCompositeType.java:486

            offset += bytesToCopy;

            // Write the end-of-component byte.
            accessor.putByte(result, offset, i != numComponents - 1 ? (byte) 0 : lastEoc);
            offset += 1;
        }
        return result;
    }

    protected ParsedComparator parseComparator(int i, String part)
    {
        return new DynamicParsedComparator(part);
    }

    protected <V> AbstractType<?> validateComparator(int i, V input, ValueAccessor<V> accessor, int offset) throws MarshalException
    {
        AbstractType<?> comparator = null;
        if (accessor.sizeFromOffset(input, offset) < 2)
            throw new MarshalException("Not enough bytes to header of the comparator part of component " + i);
        int header = accessor.getShort(input, offset);
        offset += TypeSizes.SHORT_SIZE;
        if ((header & 0x8000) == 0)
        {
            if (accessor.sizeFromOffset(input, offset) < header)
                throw new MarshalException("Not enough bytes to read comparator name of component " + i);

            V value = accessor.slice(input, offset, header);
            String valueStr = null;
            try
            {
                valueStr = accessor.toString(value);
                comparator = TypeParser.parse(valueStr);
            }
            catch (CharacterCodingException ce)
            {
                // ByteBufferUtil.string failed.
                // Log it here and we'll further throw an exception below since comparator == null

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Verify the source of the byte buffer: re-read the value from the replica or take a fresh read path instead of the truncated buffer
  2. If building composites by hand, use DynamicCompositeType.decompose(Object...) or buildDynamicComparator so headers are written correctly
  3. Run repairs/scrub on the affected range if SSTable corruption is suspected
  4. Check client/tool byte offsets: every component must start with a 2-byte header short

Example fix

// before
ByteBuffer bad = handBuiltWithoutHeader("abc"); // missing 2-byte header
// after
ByteBuffer ok = DynamicCompositeType.getInstance(aliases).decompose("abc");
Defensive patterns

Strategy: try-catch

Try / catch

try { type.validate(buffer); } catch (MarshalException e) { quarantineCorruptRecord(buffer); }

Prevention

When it happens

Trigger: Reading or validating a DynamicCompositeType value whose byte buffer ends mid-component header, e.g. from a corrupt SSTable, a truncated mutation, or hand-built byte buffers written without the 2-byte header.

Common situations: Manual construction of composite ByteBuffers that omit the comparator header; data migrated between versions with different composite encodings; corruption or truncation during manual compaction/repair tooling.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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