{"record":{"id":"ad0a62b3667ab72b","repo":"apache/cassandra","slug":"collection-column-s-can-only-be-restricted-by-con","errorCode":null,"errorMessage":"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","messagePattern":"Collection column (.+?) 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","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/restrictions/MergedRestriction.java","lineNumber":141,"sourceCode":"\n    private static void validate(SimpleRestriction restriction, SimpleRestriction other)\n    {\n        checkOperator(restriction);\n        checkOperator(other);\n\n        if (restriction.isContains() != other.isContains())\n        {\n            SimpleRestriction mapEntryRestriction = restriction.isContains() ? restriction : other;\n            if (mapEntryRestriction.isMapElementExpression())\n            {\n                ColumnMetadata column = mapEntryRestriction.firstColumn();\n                if (column.type.isFrozenCollection())\n                {\n                    throw invalidRequest(Relation.FROZEN_MAP_ENTRY_PREDICATES_NOT_SUPPORTED, column.name);\n                }\n            }\n\n            throw invalidRequest(\"Collection column %s can only be restricted by CONTAINS, CONTAINS KEY, NOT_CONTAINS, NOT_CONTAINS_KEY\" +\n                                 \" or map-entry equality if it already restricted by one of those\",\n                                 restriction.firstColumn().name);\n        }\n\n        if (restriction.isSlice() && other.isSlice())\n        {\n            ColumnMetadata firstColumn = restriction.firstColumn();\n            ColumnMetadata otherFirstColumn = other.firstColumn();\n            if (!firstColumn.equals(otherFirstColumn))\n            {\n                ColumnMetadata column = firstColumn.position() > otherFirstColumn.position() ? firstColumn\n                                                                                             : otherFirstColumn;\n\n                throw invalidRequest(\"Column \\\"%s\\\" cannot be restricted by two inequalities not starting with the same column\",\n                                     column.name);\n            }\n\n            if ((restriction.operator() == Operator.GT || restriction.operator() == Operator.GTE || restriction.operator() == Operator.BETWEEN) &&","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/restrictions/MergedRestriction.java#L123-L159","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nSELECT * FROM t WHERE tags = {'a','b'} AND size(tags) > 1; // invalid second restriction pattern\n// after\nSELECT * FROM t WHERE tags CONTAINS 'a' AND tags CONTAINS 'b' ALLOW FILTERING;","handlingStrategy":"validation","validationCode":"// ensure the first restriction on a collection column is CONTAINS-family before adding more\nRestriction merged = where.restrictionFor(col);\nif (!(merged.isContains() || merged.isMapElementExpression()))\n    throw new IllegalArgumentException(\"column \" + col.name + \" must first be restricted by CONTAINS/CONTAINS KEY\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["cql","collections","contains-operator"],"backgroundTag":"invalid-argument-value","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}