apache/cassandra · error · InvalidRequestException

cannot be used with relations

Error message

%s cannot be used with %s relations

What it means

Cassandra validates that the comparison operator used in a relation (WHERE-clause restriction) is supported for the kind of columns expression it is applied to. `Operator.validateFor(ColumnsExpression)` calls `isSupportedByRestrictionsOn`; if the operator is not allowed for that restriction kind (e.g. multi-cell slice comparisons, token, CONTAINS, or LIKE applied where unsupported), it throws naming both the operator and the relation kind.

Solutions

  1. Rewrite the relation using an operator supported for that column type (e.g. `=` or `IN` for collections, `CONTAINS`/`CONTAINS KEY` only for collections)
  2. Create the required index (e.g. a collection index with `CREATE INDEX ... ON t(ENTRIES(col))`) if the operator requires one
  3. Move the comparison into a client-side filter or into UPDATE ... IF conditions, where different operator rules apply
  4. Change the column to a type that supports the operator (e.g. use a scalar text column with SASI/LIKE support for LIKE queries)

Example fix

// before
SELECT * FROM t WHERE tags > {'a'};  -- slice on set not allowed in restrictions
// after
SELECT * FROM t WHERE tags CONTAINS 'a';
Defensive patterns

Strategy: validation

Validate before calling

// Validate operator applicability before building the relation
Set<Operator> collectionRestrictionOps = EnumSet.of(EQ, IN, CONTAINS, CONTAINS_KEY);
if (isCollectionColumn(col) && !collectionRestrictionOps.contains(op))
    throw new IllegalArgumentException("Operator " + op + " not allowed on collection restriction for " + col);
if (op == LIKE && !(col.getType().unwrap() instanceof TextType))
    throw new IllegalArgumentException("LIKE requires a text column");

Try / catch

try {
    return session.execute(query);
} catch (InvalidRequestException e) {
    if (e.getMessage().contains("cannot be used with")) {
        // fall back to an operator supported by restrictions on this column kind
        return session.execute(rewriteWithSupportedOperator(query));
    }
    throw e;
}

Prevention

When it happens

Trigger: CQL like `WHERE map_col > {..}` in a regular (non-indexed) restriction where slice operators are not permitted; using `CONTAINS`/`CONTAINS KEY` on a non-collection column; using `LIKE` on a non-text column; applying `IN` or slice operators to multi-column relations that don't support them.

Common situations: Querying a collection column with ordering operators without a suitable index (frozen + secondary index); expecting Map/List/Set ordering semantics in WHERE clauses; conditions written for conditions-column (JSON/UPDATE IF) syntax reused in SELECT restrictions where rules differ.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at src/java/org/apache/cassandra/cql3/Operator.java:978

    List<ByteBuffer> unpackMultiCellElements(MultiElementType<?> type, ByteBuffer value)
    {
        checkTrue(value != null, "Invalid comparison with null for operator \"%s\"", this);
        List<ByteBuffer> elements = type.unpack(value);
        if (type.isCollection() && elements.isEmpty())
            throw  invalidRequest("Invalid comparison with an empty %s for operator \"%s\"", ((CollectionType<?>) type).kind, this);
        return elements;
    }

    public static int serializedSize()
    {
        return 4;
    }

    public void validateFor(ColumnsExpression expression)
    {
        // this method is used only in restrictions, not in conditions where different rules apply for now
        if (!isSupportedByRestrictionsOn(expression))
            throw invalidRequest("%s cannot be used with %s relations", this, expression);

        switch (expression.kind())
        {
            case SINGLE_COLUMN:
                ColumnMetadata firstColumn = expression.firstColumn();
                AbstractType<?> columnType = firstColumn.type;
                if (isSlice() && this != Operator.NEQ)
                {
                    if (columnType.referencesDuration())
                    {
                        checkFalse(columnType.isCollection(), "Slice restrictions are not supported on collections containing durations");
                        checkFalse(columnType.isTuple(), "Slice restrictions are not supported on tuples containing durations");
                        checkFalse(columnType.isUDT(), "Slice restrictions are not supported on UDTs containing durations");
                        throw invalidRequest("Slice restrictions are not supported on duration columns");
                    }
                }
                else
                {

View on GitHub (pinned to 88fd0f6a0e)