apache/cassandra · error · MarshalException

Not enough bytes to read a set

Error message

Not enough bytes to read a set

What it means

SetSerializer.validate rejects an empty (zero-byte) value because a valid serialized set must contain at least the collection-size prefix. Cassandra historically serializes empty collections as null; a zero-length buffer is therefore treated as malformed rather than as an empty set. This guard runs during validation of values being written or bound.

Source

Thrown at src/java/org/apache/cassandra/serializers/SetSerializer.java:74

        this.elements = elements;
        this.comparators = comparators;
    }

    @Override
    public List<ByteBuffer> serializeValues(Set<T> values)
    {
        List<ByteBuffer> buffers = new ArrayList<>(values.size());
        for (T value : values)
            buffers.add(elements.serialize(value));
        buffers.sort(comparators.buffer);
        return buffers;
    }

    @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");
        }
    }

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Pass null instead of an empty buffer to unset/delete the set, or pass a properly encoded set of the elements you want.
  2. If the intent is to store an empty set, encode it with SetSerializer.serialize(Collections.emptySet()) (4-byte zero count) rather than a zero-length buffer.
  3. In test code, use the serializer's own serialize method to build valid inputs.

Example fix

// before
boundStatement.setBytes("tags", ByteBuffer.allocate(0));
// after
boundStatement.setToNull("tags"); // or
boundStatement.setSet("tags", Collections.emptySet(), String.class);
Defensive patterns

Strategy: validation

Validate before calling

// Java
if (buf == null || buf.remaining() == 0) {
    // treat as unset; bind null instead
} else {
    setSerializer.validate(buf.duplicate(), ByteBufferAccessor.instance);
}

Try / catch

try {
    setSerializer.validate(buf, ByteBufferAccessor.instance);
} catch (MarshalException e) {
    throw new IllegalArgumentException("Invalid set value: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: Binding a zero-length ByteBuffer to a set column (e.g. ByteBufferUtil.EMPTY_BYTE_BUFFER) via execute/bound statements, or validating an empty buffer in a custom type test such as setSerDerTest.

Common situations: Client drivers or app code constructing an empty set value as an empty buffer instead of null; migrations that write empty collections; custom serialization tests feeding empty input.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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