{"record":{"id":"c5afaa9abe743df2","repo":"apache/cassandra","slug":"indexrestrictions-multiple-expressions","errorCode":null,"errorMessage":"IndexRestrictions.MULTIPLE_EXPRESSIONS","messagePattern":"IndexRestrictions\\.MULTIPLE_EXPRESSIONS","errorType":"validation","errorClass":"InvalidRequestException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java","lineNumber":741,"sourceCode":"        missingClusteringColumns.removeAll(new LinkedList<>(clusteringColumnsRestrictions.columns()));\n        return ColumnMetadata.toIdentifiers(missingClusteringColumns);\n    }\n\n    /**\n     * Checks if some clustering columns are not restricted.\n     * @return <code>true</code> if some clustering columns are not restricted, <code>false</code> otherwise.\n     */\n    private boolean hasUnrestrictedClusteringColumns()\n    {\n        return table.clusteringColumns().size() != clusteringColumnsRestrictions.size();\n    }\n\n    private void processCustomIndexExpressions(List<CustomIndexExpression> expressions,\n                                               VariableSpecifications boundNames,\n                                               IndexRegistry indexRegistry)\n    {\n        if (expressions.size() > 1 && !indexRegistry.supportsMultipleIndexExpressions())\n            throw new InvalidRequestException(IndexRestrictions.MULTIPLE_EXPRESSIONS);\n\n        for (CustomIndexExpression expression : expressions)\n        {\n            QualifiedName name = expression.targetIndex;\n\n            if (name.hasKeyspace() && !name.getKeyspace().equals(table.keyspace))\n                throw IndexRestrictions.invalidIndex(expression.targetIndex, table);\n\n            if (!table.indexes.has(expression.targetIndex.getName()))\n                throw IndexRestrictions.indexNotFound(expression.targetIndex, table);\n\n            Index index = indexRegistry.getIndex(table.indexes.get(expression.targetIndex.getName()).get());\n            if (!index.getIndexMetadata().isCustom())\n                throw IndexRestrictions.nonCustomIndexInExpression(expression.targetIndex);\n\n            AbstractType<?> expressionType = index.customExpressionValueType();\n            if (expressionType == null)\n                throw IndexRestrictions.customExpressionNotSupported(expression.targetIndex);","sourceCodeStart":723,"sourceCodeEnd":759,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java#L723-L759","documentation":"Custom index expressions (the legacy 'expr(idx, ...)' syntax) may only be used with indexes that support multiple expressions; otherwise at most one expression per statement is allowed. processCustomIndexExpressions throws IndexRestrictions.MULTIPLE_EXPRESSIONS when more than one expression is given and the target index backend does not declare support.","triggerScenarios":"A SELECT with two or more CustomIndexExpression terms (e.g. expr(myidx, 'a'), expr(myidx, 'b')) against a custom index implementation whose supportsMultipleIndexExpressions() returns false (e.g. plain StorageAttachedIndex vs. legacy index backends).","commonSituations":"Using Lucene/other third-party index syntax patterns that accept multiple conditions, against an index implementation that only handles a single expression.","solutions":["Combine the conditions into a single expression string if the index supports it (e.g. one expr with a compound query).","Remove the extra expressions and filter remaining conditions client-side or with normal WHERE clauses.","Switch to an index implementation that supports multiple index expressions."],"exampleFix":"// before\nSELECT * FROM t WHERE expr(idx, 'age > 30'), expr(idx, 'city = Paris');\n// after\nSELECT * FROM t WHERE expr(idx, 'age > 30 AND city = Paris');","handlingStrategy":"validation","validationCode":"if (customExpressions.size() > 1 && !indexSupportsMultipleExpressions)\n    throw new IllegalArgumentException(\"target index supports only a single custom expression\");","typeGuard":null,"tryCatchPattern":"try { session.execute(stmt); }\ncatch (InvalidRequestException e) {\n    if (e.getMessage().contains(\"multiple expressions\")) { /* merge conditions into one expr */ }\n    else throw e;\n}","preventionTips":["Check the index implementation's supportsMultipleIndexExpressions() capability before composing queries.","Combine conditions into a single expression where the backend allows.","Prefer modern SAI/standard WHERE predicates over legacy expr() syntax."],"tags":["cassandra","cql","custom-index","restrictions"],"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"}