{"record":{"id":"c3be960d0ea26408","repo":"apache/cassandra","slug":"s-restriction-is-only-supported-on-properly-index","errorCode":null,"errorMessage":"%s restriction is only supported on properly indexed columns. %s is not valid.","messagePattern":"(.+?) restriction is only supported on properly indexed columns\\. (.+?) is not valid\\.","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java","lineNumber":239,"sourceCode":"            Operator operator = relation.operator();\n            if (operator.requiresFilteringOrIndexingFor(ColumnMetadata.Kind.CLUSTERING) && (type.isUpdate() || type.isDelete()))\n            {\n                throw invalidRequest(\"Cannot use %s with %s\", type, operator);\n            }\n\n            if (operator == Operator.IS_NOT)\n            {\n                if (!forView)\n                    throw new InvalidRequestException(\"Unsupported restriction: \" + relation);\n\n                this.notNullColumns.addAll(relation.toRestriction(table, boundNames, owner, allowFiltering).columns());\n            }\n            else if (operator.requiresIndexing())\n            {\n                Restriction restriction = relation.toRestriction(table, boundNames, owner, allowFiltering);\n\n                if (!type.allowUseOfSecondaryIndices() || !restriction.hasSupportingIndex(indexRegistry, indexHints))\n                    throw invalidRequest(\"%s restriction is only supported on properly \" +\n                                                        \"indexed columns. %s is not valid.\", operator, relation);\n\n                addRestriction(restriction, indexRegistry, indexHints);\n            }\n            else\n            {\n                addRestriction(relation.toRestriction(table, boundNames, owner, allowFiltering), indexRegistry, indexHints);\n            }\n        }\n\n        // ORDER BY clause.\n        // Some indexes can be used for ordering.\n        nonPrimaryKeyRestrictions = addOrderingRestrictions(orderings, nonPrimaryKeyRestrictions);\n\n        hasRegularColumnsRestrictions = nonPrimaryKeyRestrictions.hasRestrictionFor(ColumnMetadata.Kind.REGULAR);\n\n        boolean hasQueriableClusteringColumnIndex = false;\n        boolean hasQueriableIndex = false;","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java#L221-L257","documentation":"Thrown when a relation uses an operator that requires indexing (e.g. CONTAINS, or non-equality operators on regular columns) but no suitable secondary index supports that restriction, or secondary indices are not permitted for this statement type. Cassandra will not perform unindexed scans implicitly.","triggerScenarios":"`SELECT * FROM t WHERE regular_col = x` without ALLOW FILTERING and without an index; CONTAINS on a collection without a collection index; using such restrictions in statement types that disallow secondary indices; index exists but the relation's operator/column is not covered by it.","commonSituations":"Querying a column that was never indexed; index created on a different column than the one in the WHERE clause; SASI/SAI vs legacy 2i confusion after upgrades; forgetting ALLOW FILTERING during ad-hoc analysis.","solutions":["Create a supporting secondary index: CREATE INDEX ON t (regular_col) (or an index covering the collection/operator used).","Add ALLOW FILTERING if the table is small and an unindexed scan is acceptable (performance risk on large tables).","Verify with the index registry/schema that the index actually covers the column and operator used in the relation.","Model the query instead: denormalize into a query table with the filtered column in the primary key."],"exampleFix":"// before\nSELECT * FROM t WHERE email = 'a@b.c'; -- no index\n// after\nCREATE INDEX ON t (email);\nSELECT * FROM t WHERE email = 'a@b.c';","handlingStrategy":"validation","validationCode":"// before querying, verify an index covers the column\nboolean indexed = schemaKeyspaces.get(ks).getTables().get(t).getIndexes().values().stream()\n    .anyMatch(i -> i.getTarget().equals(columnName));\nif (!indexed) { createIndex(); }","typeGuard":null,"tryCatchPattern":"try { session.execute(query); } catch (InvalidRequestException e) { if (e.getMessage().contains(\"only supported on properly indexed\")) runWithAllowFiltering(); else throw e; }","preventionTips":["Model tables per query; keep high-frequency predicates in the primary key.","Check schema metadata for index coverage at startup.","Reserve ALLOW FILTERING for small tables and ad-hoc analysis."],"tags":["cql","invalid-request","secondary-index","filtering"],"backgroundTag":"missing-required-index","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"}