{"record":{"id":"2f5e29f4e0a86929","repo":"apache/cassandra","slug":"ann-ordering-by-vector-requires-the-column-to-be-i","errorCode":null,"errorMessage":"ANN ordering by vector requires the column to be indexed","messagePattern":"ANN ordering by vector requires the column to be indexed","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java","lineNumber":334,"sourceCode":"                Collection<ColumnIdentifier> nonPrimaryKeyColumns =\n                        ColumnMetadata.toIdentifiers(nonPrimaryKeyRestrictions.columns());\n\n                throw invalidRequest(\"Non PRIMARY KEY columns found in where clause: %s \",\n                                     Joiner.on(\", \").join(nonPrimaryKeyColumns));\n            }\n\n            Optional<SingleRestriction> annRestriction = Streams.stream(nonPrimaryKeyRestrictions)\n                                                                .filter(SingleRestriction::isANN)\n                                                                .findFirst();\n            if (annRestriction.isPresent())\n            {\n                // If there is an ANN restriction then it must be for a vector<float, n> column, and it must have an index\n                ColumnMetadata annColumn = annRestriction.get().firstColumn();\n\n                if (!annColumn.type.isVector() || !(((VectorType<?>)annColumn.type).elementType instanceof FloatType))\n                    throw invalidRequest(ANN_ONLY_SUPPORTED_ON_VECTOR_MESSAGE);\n                if (indexRegistry == null || indexRegistry.listIndexes().stream().noneMatch(i -> i.dependsOn(annColumn)))\n                    throw invalidRequest(ANN_REQUIRES_INDEX_MESSAGE);\n                // We do not allow ANN queries using partition key restrictions that need filtering\n                if (partitionKeyRestrictions.needFiltering())\n                    throw invalidRequest(ANN_REQUIRES_INDEXED_FILTERING_MESSAGE);\n                // We do not allow ANN query filtering using non-indexed columns\n                List<ColumnMetadata> nonAnnColumns = Streams.stream(nonPrimaryKeyRestrictions)\n                                                            .filter(r -> !r.isANN())\n                                                            .map(SingleRestriction::firstColumn)\n                                                            .collect(Collectors.toList());\n                List<ColumnMetadata> clusteringColumns = clusteringColumnsRestrictions.columns();\n                if (!nonAnnColumns.isEmpty() || !clusteringColumns.isEmpty())\n                {\n                    List<ColumnMetadata> nonIndexedColumns = Stream.concat(nonAnnColumns.stream(), clusteringColumns.stream())\n                                                                   .filter(c -> indexRegistry.listIndexes().stream().noneMatch(i -> i.dependsOn(c)))\n                                                                   .collect(Collectors.toList());\n                    if (!nonIndexedColumns.isEmpty())\n                    {\n                        // restrictions on non-clustering columns, or clusterings that still need filtering, are invalid\n                        if (!clusteringColumns.containsAll(nonIndexedColumns)","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java#L316-L352","documentation":"Thrown when an ANN ordering is requested on a valid float vector column that has no index attached (or no index registry is available). ANN search is executed through a vector index (SAI/COSINE etc.); without one, Cassandra cannot perform approximate nearest-neighbor search.","triggerScenarios":"`SELECT * FROM t ORDER BY v ANN OF [0.1,...]` where no `CREATE INDEX ... USING ... ON t(v)` exists, or the index was dropped, or the statement runs in a context without an index registry.","commonSituations":"Freshly created table queried before index build completed; index dropped during maintenance; tests with un-indexed tables; index created on a different vector column.","solutions":["Create a vector index: CREATE INDEX ON t (v) USING 'sai' (or the storage-attached index form for vectors).","Wait for the index to become queryable/build-complete before running ANN queries.","Confirm the index depends on the exact ANN column (not another column) via schema metadata.","If no index is desired, fetch rows and compute similarity client-side instead of ANN."],"exampleFix":"// before\nSELECT * FROM t ORDER BY v ANN OF [0.1, 0.2]; -- no index on v\n// after\nCREATE INDEX ann_idx ON t (v) USING 'sai' WITH OPTIONS = { 'similarity_function': 'cosine' };\nSELECT * FROM t ORDER BY v ANN OF [0.1, 0.2] LIMIT 5;","handlingStrategy":"validation","validationCode":"boolean hasVectorIndex = table.getIndexes().values().stream()\n    .anyMatch(i -> i.getTarget().equals(vectorColumn));\nif (!hasVectorIndex) throw new IllegalStateException(\"create a vector index on \" + vectorColumn + \" before ANN queries\");","typeGuard":null,"tryCatchPattern":"try { session.execute(annQuery); } catch (InvalidRequestException e) { if (e.getMessage().contains(\"requires the column to be indexed\")) { createVectorIndex(); waitForIndex(); retry(); } else throw e; }","preventionTips":["Provision vector indexes as part of table bootstrap/migration scripts.","Wait for index build completion before serving ANN traffic.","Include index existence in health checks."],"tags":["cql","ann","vector-index","sai"],"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"}