{"record":{"id":"9f9a3b2dab23dd11","repo":"apache/cassandra","slug":"operator-s-is-only-supported-in-intersections-for","errorCode":null,"errorMessage":"Operator %s is only supported in intersections for reads that do not require replica reconciliation.","messagePattern":"Operator (.+?) is only supported in intersections for reads that do not require replica reconciliation\\.","errorType":"exception","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/index/sai/plan/StorageAttachedIndexQueryPlan.java","lineNumber":90,"sourceCode":"        ImmutableSet.Builder<Index> selectedIndexesBuilder = ImmutableSet.builder();\n\n        RowFilter indexFilter = filter;\n        RowFilter postIndexFilter = filter;\n\n        for (RowFilter.Expression expression : filter)\n        {\n            // We ignore any expressions here (user-defined expressions and SAI unsupported operators) where we don't have a way to\n            // translate their #isSatifiedBy method, they will be included in the filter returned by \n            // QueryPlan#postIndexQueryFilter(). If strict filtering is not allowed, we must reject the query until the\n            // expression(s) in question are compatible with #isSatifiedBy.\n            //\n            // Note: For both the pre- and post-filters we need to check that the expression exists before removing it\n            // because the without method assert if the expression doesn't exist. This can be the case if we are given\n            // a duplicate expression - a = 1 and a = 1. The without method removes all instances of the expression.\n            if (!Expression.supportsOperator(expression.operator()) || expression.isUserDefined())\n            {\n                if (!filter.isStrict())\n                    throw new InvalidRequestException(String.format(UNSUPPORTED_NON_STRICT_OPERATOR, expression.operator()));\n\n                if (indexFilter.getExpressions().contains(expression))\n                    indexFilter = indexFilter.without(expression);\n                continue;\n            }\n\n            if (postIndexFilter.getExpressions().contains(expression))\n                postIndexFilter = postIndexFilter.without(expression);\n\n            for (StorageAttachedIndex index : indexes)\n            {\n                if (index.supportsExpression(expression) && !filter.indexHints.excludes(index))\n                {\n                    selectedIndexesBuilder.add(index);\n                }\n            }\n        }\n","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/index/sai/plan/StorageAttachedIndexQueryPlan.java#L72-L108","documentation":"StorageAttachedIndexQueryPlan.create only supports operators that SAI can answer (Expression.supportsOperator) inside strict (replica-reconciled) filters; user-defined expressions are also rejected. When such an expression appears in a non-strict filter context, it throws InvalidRequestException saying the operator is only supported in intersections for reads that don't require replica reconciliation.","triggerScenarios":"Issuing a query where an SAI operator (or a user-defined expression) appears in a filter position requiring replica reconciliation (e.g. with per-replica reconciliation / non-intersection reads), rather than a plain strict intersection.","commonSituations":"Mixing SAI-indexed predicates with features that weaken read consistency assumptions (e.g. certain ranges/tombstone-reconciliation reads); using custom index expressions alongside SAI operators; CL tuning (e.g. CL=ONE with strong-consistency features) that triggers reconciliation paths.","solutions":["Restructure the query so SAI predicates form a single intersection without reconciliation-requiring operators","Remove user-defined (custom index) expressions from the SAI query","Change consistency level / query form so replica reconciliation is not required","Use ALLOW FILTERING or a non-indexed path if appropriate"],"exampleFix":"// before\nSELECT * FROM t WHERE a = 1 AND custom_expr(b) = 'x'; // unsupported operator in strict/reconciliation path\n// after\nSELECT * FROM t WHERE a = 1; // then post-filter custom expression client-side","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    session.execute(cql);\n} catch (InvalidRequestException e) {\n    if (e.getMessage().contains(\"only supported in intersections\")) {\n        // restructure query into strict intersection or post-filter client-side\n    }\n}","preventionTips":["Keep SAI predicates in plain AND intersections","Avoid user-defined/custom expressions mixed with SAI operators","Verify consistency-level and query form don't trigger replica reconciliation"],"tags":["sai","query-planning","invalid-request","consistency"],"backgroundTag":"unsupported-operation","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}