apache/cassandra · error · InvalidRequestException
Collection column can only be restricted by CONTAINS…
Error message
Collection column %s can only be restricted by CONTAINS, CONTAINS KEY, NOT_CONTAINS, NOT_CONTAINS_KEY or map-entry equality if it already restricted by one of those
What it means
When two restrictions on the same collection column are merged, at least one must be a CONTAINS, CONTAINS KEY, NOT_CONTAINS or NOT_CONTAINS_KEY (or a map-entry equality already anchored by those). MergedRestriction.validate throws this when a second, unrelated restriction (e.g. EQ or slice) is combined with a collection restriction that does not permit it, since such filtering cannot be served by the collection indexes.
Solutions
- Ensure at least one restriction on the column is CONTAINS / CONTAINS KEY / NOT_CONTAINS / NOT_CONTAINS KEY (with an index) before adding further predicates
- Use a map-entry equality on a non-frozen map instead of full-collection comparisons
- Restructure the query or data model (denormalize the collection entries into rows) so each predicate targets a simple column
Example fix
// before
SELECT * FROM t WHERE tags = {'a','b'} AND size(tags) > 1; // invalid second restriction pattern
// after
SELECT * FROM t WHERE tags CONTAINS 'a' AND tags CONTAINS 'b' ALLOW FILTERING; Defensive patterns
Strategy: validation
Validate before calling
// ensure the first restriction on a collection column is CONTAINS-family before adding more
Restriction merged = where.restrictionFor(col);
if (!(merged.isContains() || merged.isMapElementExpression()))
throw new IllegalArgumentException("column " + col.name + " must first be restricted by CONTAINS/CONTAINS KEY"); Prevention
- Build collection predicates only via a query-builder that enforces CONTAINS-first ordering
- Create the required CONTAINS/SAI indexes before using CONTAINS predicates
- Limit one well-supported predicate style per collection column in application queries
When it happens
Trigger: A query adding a second restriction on a collection column where neither merged side is a CONTAINS-family operator nor a valid map-entry expression — e.g. tags = {...} AND tags CONTAINS 'x' is fine, but merging two non-contains restrictions, or a slice plus EQ on a collection column, reaches this throw.
Common situations: Combining full-collection equality with other predicates in ad-hoc CQL; ORM/query-builders emitting multiple predicates on the same list/set/map column; users expecting SQL-style arbitrary column predicates.
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
- appendAll() can only be called on non-frozen collections
- Cannot create index on
- Cannot create () index on frozen column . Frozen…
- Cannot create () index on . Non-collection columns only…
- Constraint cannot be defined on the column
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/ad0a62b3667ab72b.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/cql3/restrictions/MergedRestriction.java:141
private static void validate(SimpleRestriction restriction, SimpleRestriction other)
{
checkOperator(restriction);
checkOperator(other);
if (restriction.isContains() != other.isContains())
{
SimpleRestriction mapEntryRestriction = restriction.isContains() ? restriction : other;
if (mapEntryRestriction.isMapElementExpression())
{
ColumnMetadata column = mapEntryRestriction.firstColumn();
if (column.type.isFrozenCollection())
{
throw invalidRequest(Relation.FROZEN_MAP_ENTRY_PREDICATES_NOT_SUPPORTED, column.name);
}
}
throw invalidRequest("Collection column %s can only be restricted by CONTAINS, CONTAINS KEY, NOT_CONTAINS, NOT_CONTAINS_KEY" +
" or map-entry equality if it already restricted by one of those",
restriction.firstColumn().name);
}
if (restriction.isSlice() && other.isSlice())
{
ColumnMetadata firstColumn = restriction.firstColumn();
ColumnMetadata otherFirstColumn = other.firstColumn();
if (!firstColumn.equals(otherFirstColumn))
{
ColumnMetadata column = firstColumn.position() > otherFirstColumn.position() ? firstColumn
: otherFirstColumn;
throw invalidRequest("Column \"%s\" cannot be restricted by two inequalities not starting with the same column",
column.name);
}
if ((restriction.operator() == Operator.GT || restriction.operator() == Operator.GTE || restriction.operator() == Operator.BETWEEN) &&View on GitHub (pinned to 88fd0f6a0e)