{"record":{"id":"7c52ca2be3f2c017","repo":"apache/cassandra","slug":"query-s-attempted-to-read-from-too-many-indexes","errorCode":null,"errorMessage":"Query %s attempted to read from too many indexes (%s) but max allowed is %s; query aborted (see sai_sstable_indexes_per_query_fail_threshold)","messagePattern":"Query (.+?) attempted to read from too many indexes \\((.+?)\\) but max allowed is (.+?); query aborted \\(see sai_sstable_indexes_per_query_fail_threshold\\)","errorType":"exception","errorClass":"QueryReferencingTooManyIndexesException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/index/sai/plan/QueryController.java","lineNumber":357,"sourceCode":"\n    void maybeTriggerGuardrails(QueryViewBuilder.QueryView queryView)\n    {\n        int referencedIndexes = 0;\n\n        // We want to make sure that no individual column expression touches too many SSTable-attached indexes:\n        for (QueryViewBuilder.QueryExpressionView expressionSSTables : queryView.view)\n            referencedIndexes = Math.max(referencedIndexes, expressionSSTables.sstableIndexes.size());\n\n        if (Guardrails.saiSSTableIndexesPerQuery.failsOn(referencedIndexes, null))\n        {\n            String msg = String.format(\"Query %s attempted to read from too many indexes (%s) but max allowed is %s; \" +\n                                       \"query aborted (see sai_sstable_indexes_per_query_fail_threshold)\",\n                                       command.toCQLString(),\n                                       referencedIndexes,\n                                       Guardrails.CONFIG_PROVIDER.getOrCreate(null).getSaiSSTableIndexesPerQueryFailThreshold());\n            Tracing.trace(msg);\n            MessageParams.add(ParamType.TOO_MANY_REFERENCED_INDEXES_FAIL, referencedIndexes);\n            throw new QueryReferencingTooManyIndexesException(msg);\n        }\n        else if (Guardrails.saiSSTableIndexesPerQuery.warnsOn(referencedIndexes, null))\n        {\n            MessageParams.add(ParamType.TOO_MANY_REFERENCED_INDEXES_WARN, referencedIndexes);\n        }\n    }\n\n    /**\n     * Returns whether this query is not selecting the {@link PrimaryKey}.\n     * The query does not select the key if both of the following statements are false:\n     *  1. The table associated with the query is not using clustering keys\n     *  2. The clustering index filter for the command wants the row.\n     * <p>\n     *  Item 2 is important in paged queries where the {@link org.apache.cassandra.db.filter.ClusteringIndexSliceFilter} for\n     *  subsequent paged queries may not select rows that are returned by the index\n     *  search because that is initially partition based.\n     *\n     * @param key The {@link PrimaryKey} to be tested","sourceCodeStart":339,"sourceCodeEnd":375,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/index/sai/plan/QueryController.java#L339-L375","documentation":"QueryController.guardrails aborts a query that would need to reference more SAI SSTable indexes than the sai_sstable_indexes_per_query_fail_threshold guardrail allows. It throws QueryReferencingTooManyIndexesException with the CQL string, index count, and configured threshold. A lower warning threshold logs a warning instead.","triggerScenarios":"Running a SELECT whose WHERE clause spans indexes that collectively reference more distinct SSI (SSTable-attached indexes) per query than the fail threshold configured in guardrails.","commonSituations":"Queries filtering on many indexed columns at once in a large cluster with many SSTables; thresholds lowered for resource protection; after bulk loading, many small SSTables multiply referenced index counts.","solutions":["Reduce the number of indexed columns in the query's WHERE clause","Raise sai_sstable_indexes_per_query_fail_threshold via guardrails if resources allow","Compact SSTables to reduce the number of referenced SSTable indexes","Split the query into fewer indexed predicates"],"exampleFix":"// before\nSELECT * FROM t WHERE a = 1 AND b = 2 AND c = 3 AND d = 4; // exceeds threshold\n// after\nALTER TABLE guardrails SETTINGS ...; -- or via cassandra.yaml:\n-- raise sai_sstable_indexes_per_query_fail_threshold, or query fewer columns:\nSELECT * FROM t WHERE a = 1 AND b = 2;","handlingStrategy":"validation","validationCode":"int referenced = countSaiIndexesInWhereClause(cql); // client-side count\nif (referenced > maxThreshold) splitQuery();","typeGuard":null,"tryCatchPattern":"try {\n    session.execute(cql);\n} catch (QueryReferencingTooManyIndexesException e) {\n    // reduce indexed predicates or raise the guardrail threshold\n}","preventionTips":["Limit multi-column SAI-filtered queries","Track guardrail settings in cluster config reviews","Compact SSTables regularly to limit SSTable index fan-out"],"tags":["sai","guardrails","query-planning","threshold"],"backgroundTag":"value-out-of-range","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"}