apache/cassandra · error · InvalidRequestException
IndexRestrictions.MULTIPLE_EXPRESSIONS
Error message
IndexRestrictions.MULTIPLE_EXPRESSIONS
What it means
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.
Source
Thrown at src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java:741
missingClusteringColumns.removeAll(new LinkedList<>(clusteringColumnsRestrictions.columns()));
return ColumnMetadata.toIdentifiers(missingClusteringColumns);
}
/**
* Checks if some clustering columns are not restricted.
* @return <code>true</code> if some clustering columns are not restricted, <code>false</code> otherwise.
*/
private boolean hasUnrestrictedClusteringColumns()
{
return table.clusteringColumns().size() != clusteringColumnsRestrictions.size();
}
private void processCustomIndexExpressions(List<CustomIndexExpression> expressions,
VariableSpecifications boundNames,
IndexRegistry indexRegistry)
{
if (expressions.size() > 1 && !indexRegistry.supportsMultipleIndexExpressions())
throw new InvalidRequestException(IndexRestrictions.MULTIPLE_EXPRESSIONS);
for (CustomIndexExpression expression : expressions)
{
QualifiedName name = expression.targetIndex;
if (name.hasKeyspace() && !name.getKeyspace().equals(table.keyspace))
throw IndexRestrictions.invalidIndex(expression.targetIndex, table);
if (!table.indexes.has(expression.targetIndex.getName()))
throw IndexRestrictions.indexNotFound(expression.targetIndex, table);
Index index = indexRegistry.getIndex(table.indexes.get(expression.targetIndex.getName()).get());
if (!index.getIndexMetadata().isCustom())
throw IndexRestrictions.nonCustomIndexInExpression(expression.targetIndex);
AbstractType<?> expressionType = index.customExpressionValueType();
if (expressionType == null)
throw IndexRestrictions.customExpressionNotSupported(expression.targetIndex);View on GitHub (pinned to 88fd0f6a0e)
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.
Example fix
// before SELECT * FROM t WHERE expr(idx, 'age > 30'), expr(idx, 'city = Paris'); // after SELECT * FROM t WHERE expr(idx, 'age > 30 AND city = Paris');
Defensive patterns
Strategy: validation
Validate before calling
if (customExpressions.size() > 1 && !indexSupportsMultipleExpressions)
throw new IllegalArgumentException("target index supports only a single custom expression"); Try / catch
try { session.execute(stmt); }
catch (InvalidRequestException e) {
if (e.getMessage().contains("multiple expressions")) { /* merge conditions into one expr */ }
else throw e;
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: Using Lucene/other third-party index syntax patterns that accept multiple conditions, against an index implementation that only handles a single expression.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- WHERE clause for materialized view '%s' cannot contain custo
- category %s not found in %s
- GRANT operation is not supported by AllowAllAuthorizer
- REVOKE operation is not supported by AllowAllAuthorizer
- LIST PERMISSIONS operation is not supported by AllowAllAutho
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/c5afaa9abe743df2.
Report an issue: GitHub.