apache/cassandra · error · MarshalException
Invalid unset value for field
Error message
Invalid unset value for field '%s' of user defined type %s
What it means
Unset sentinel values are only legal for multi-cell (non-frozen) UDTs. While validating elements, if the type is frozen (not multiCell) and a field's buffer equals the unset sentinel, this MarshalException names the field and type, because frozen values must be written in full.
Solutions
- Provide an explicit value for every field of the frozen UDT (use null to overwrite with an empty field if desired)
- Unfreeze the UDT (recreate as multi-cell) if partial updates with unset are required
- Check each buffer for the unset sentinel before constructing the value
Example fix
// before
buffers.set(1, Unset); // frozen UDT -> MarshalException
// after
if (!udt.isMultiCell() && buffer == unsetValue)
buffer = fieldDefault; // explicit value instead of unset
buffers.set(1, buffer); Defensive patterns
Strategy: validation
Validate before calling
if (!udt.isMultiCell()) for (int i=0;i<buffers.size();i++) if (buffers.get(i) == unsetValue) throw new IllegalArgumentException("unset not allowed for frozen field " + udt.fieldNameAsString(i)); Type guard
boolean unsetAllowed(UserType udt, Object buffer) { return udt.isMultiCell() || buffer != unsetValue; } Try / catch
try { v = new UserType.Value(udt, buffers); } catch (MarshalException e) { throw new BindingException("frozen UDT cannot contain unset fields"); } Prevention
- Never use unset() with frozen UDT columns
- Provide complete values for frozen types; recreate the UDT as non-frozen for partial updates
- Detect unset sentinels at the binding layer
When it happens
Trigger: Binding UNSET_BYTE_ARRAY / unset for a field of a frozen UDT in a constructor path; a prepared-statement bind variable left 'unset' for a frozen UDT field.
Common situations: Client using unset() on frozen UDT fields hoping to preserve existing values (explicitly unsupported); ORM-generated binds defaulting to unset; migration of code that worked when the UDT was later changed to frozen.
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
- Invalid operation ( ) for frozen UDT column
- A user type cannot contain non-frozen UDTs
- Altering field types is no longer supported
- Argument ' ' cannot be frozen; remove frozen<> modifier from
- Cannot add new field
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/22d3ed9fc6106015.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/db/marshal/UserType.java:697
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("UDT value contained too many fields (expected %s, got %s)", size(), buffers.size()));
for (int i = 0; i < buffers.size(); i++)
{
// Since a frozen UDT 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 (!isMultiCell() && buffer == unsetValue)
throw new MarshalException(String.format("Invalid unset value for field '%s' of user defined type %s", fieldNameAsString(i), getNameAsString()));
type(i).validate(buffer, valueAccessor);
}
return buffers;
}
@Override
public SchemaElementType elementType()
{
return SchemaElementType.TYPE;
}
@Override
public String elementKeyspace()
{
return keyspace;
}
View on GitHub (pinned to 88fd0f6a0e)