apache/cassandra · error · InvalidRequestException

Invalid operation (%s) for non-UDT column %s

Error message

Invalid operation (%s) for non-UDT column %s

What it means

Cassandra throws this during preparation when a UDT field-update operation (udt.field = value) targets a column that is not a user-defined type. Only non-frozen UDT columns support per-field assignment; any other column type is rejected before field resolution.

Source

Thrown at src/java/org/apache/cassandra/cql3/Operation.java:297

            return !(other instanceof SetValue);
        }
    }

    public static class SetField implements RawUpdate
    {
        private final FieldIdentifier field;
        private final Term.Raw value;

        public SetField(FieldIdentifier field, Term.Raw value)
        {
            this.field = field;
            this.value = value;
        }

        public Operation prepare(TableMetadata metadata, ColumnMetadata receiver, boolean canReadExistingState) throws InvalidRequestException
        {
            if (!receiver.type.isUDT())
                throw new InvalidRequestException(String.format("Invalid operation (%s) for non-UDT column %s", toString(receiver), receiver.name));
            else if (!receiver.type.isMultiCell())
                throw new InvalidRequestException(String.format("Invalid operation (%s) for frozen UDT column %s", toString(receiver), receiver.name));

            int fieldPosition = ((UserType) receiver.type).fieldPosition(field);
            if (fieldPosition == -1)
                throw new InvalidRequestException(String.format("UDT column %s does not have a field named %s", receiver.name, field));

            Term val = value.prepare(metadata.keyspace, UserTypes.fieldSpecOf(receiver, fieldPosition));
            return new UserTypes.SetterByField(receiver, field, val);
        }

        protected String toString(ColumnSpecification column)
        {
            return String.format("%s.%s = %s", column.name, field, value);
        }

        public boolean isCompatibleWith(RawUpdate other)
        {

View on GitHub (pinned to 88fd0f6a0e)

Solutions

  1. Confirm the column type with DESCRIBE TABLE; use plain assignment for non-UDT columns
  2. If field-wise updates are wanted, change the column to a (non-frozen) UDT and migrate data
  3. For tuples, replace the whole tuple value instead of assigning a field

Example fix

// before (address is tuple<text,text>)
UPDATE users SET address.city = 'NYC' WHERE id = 1;
// after
UPDATE users SET address = ('NYC','10001') WHERE id = 1;  -- replace whole tuple
Defensive patterns

Strategy: validation

Validate before calling

AbstractType<?> t = tm.getColumn(col).getType();
if (!t.isUDT()) throw new IllegalArgumentException(col + " is not a UDT; use plain assignment");

Type guard

boolean isUdt(AbstractType<?> t) { return t.isUDT(); }

Prevention

When it happens

Trigger: Executing 'UPDATE t SET mycol.fieldname = v WHERE ...' where mycol is not a UDT (scalar, collection, tuple); e.g. using field syntax on a tuple or text column.

Common situations: Column type confusion between tuple and UDT (both use dot-notation concepts); schema changed from UDT to another type; copy-pasted queries across tables.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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