apache/cassandra · error · InvalidRequestException

Invalid unset value for tuple field number

Error message

Invalid unset value for tuple field number %d

What it means

During filterSortAndValidateElements, a field buffer equal to the sentinel unset marker (UNSET_BYTE_ARRAY) is rejected with InvalidRequestException. Cassandra writes tuples in their entirety, so an 'unset' individual field cannot preserve a previous value; the driver must instead omit or fully supply the tuple.

Solutions

  1. Supply a complete tuple value (all fields set, or the whole tuple null) instead of per-field unset markers
  2. Rewrite the update to replace the whole tuple in one statement
  3. If a partial update is needed, read-modify-write: SELECT the tuple, merge in the app, UPDATE the full value
  4. Check driver documentation for how it encodes unset values and avoid it for tuple fields

Example fix

// before: binding with unset field
stmt.bind(id, UNSET, value);
// after: bind the whole tuple or null
TupleValue full = elementType.newValue(null, value); // explicit full tuple
stmt.bind(id, full);
Defensive patterns

Strategy: validation

Validate before calling

for (Object f : fields)
    if (f == null || isUnsetMarker(f))
        throw new IllegalArgumentException("tuples cannot contain unset fields; supply the full value");

Try / catch

try {
    tupleType.bind(fields);
} catch (InvalidRequestException e) {
    // unset field inside tuple: rewrite as full tuple or whole-column update
}

Prevention

When it happens

Trigger: Binding a query where a driver sends an unset marker for one tuple element (common when using bind markers with partial assignment); calling filterSortAndValidateElements with the unset sentinel present in the buffers list.

Common situations: Using prepared statements where some bound variables are left unset inside a tuple value; ORMs or client libraries that map nulls to unset markers; partial-update logic applied to a tuple column.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/db/marshal/TupleType.java:417

    @Override
    public List<byte[]> filterSortAndValidateElementsFromArrays(List<byte[]> buffers)
    {
        return filterSortAndValidateElements(buffers, ByteArrayUtil.UNSET_BYTE_ARRAY, ByteArrayAccessor.instance);
    }

    private <T> List<T> filterSortAndValidateElements(List<T> buffers, T unsetValue, ValueAccessor<T> valueAccessor)
    {
        if (buffers.size() > size())
            throw new MarshalException(String.format("Tuple value contains too many fields (expected %s, got %s)", size(), buffers.size()));

        for (int i = 0; i < buffers.size(); i++)
        {
            // Since A tuple value is always written in its entirety Cassandra can't preserve a pre-existing value by 'not setting' the new value. Reject the query.
            T buffer = buffers.get(i);
            if (buffer == null)
                continue;
            if (buffer == unsetValue)
                throw new InvalidRequestException(String.format("Invalid unset value for tuple field number %d", i));
            type(i).validate(buffer, valueAccessor);
        }

        return buffers;
    }

    @Override
    public <V> String getString(V input, ValueAccessor<V> accessor)
    {
        if (input == null)
            return "null";

        StringBuilder sb = new StringBuilder();
        int offset = 0;
        for (int i = 0; i < size(); i++)
        {
            if (accessor.isEmptyFromOffset(input, offset))
                return sb.toString();

View on GitHub (pinned to 88fd0f6a0e)