spring-projects/spring-ai · error · RuntimeException
Not supported expression type:
Error message
Not supported expression type:
What it means
AzureAiSearchFilterExpressionConverter.getOperationSymbol translates Spring AI Filter.Expression types into Azure AI Search OData operator strings (lt, le, gt, ge, search.in). If the expression's type is not one of the six supported comparison types (e.g. AND, OR, NOT passed here unexpectedly), the default branch throws a RuntimeException naming the unsupported type. This is a defensive guard: group types should be routed elsewhere before reaching this switch.
Source
Thrown at vector-stores/spring-ai-azure-store/src/main/java/org/springframework/ai/vectorstore/azure/AzureAiSearchFilterExpressionConverter.java:90
}
protected void doEndValueRange(Filter.Value listValue, StringBuilder context) {
context.append("'");
}
private String getOperationSymbol(Expression exp) {
return switch (exp.type()) {
case AND -> " and ";
case OR -> " or ";
case EQ -> " eq ";
case NE -> " ne ";
case LT -> " lt ";
case LTE -> " le ";
case GT -> " gt ";
case GTE -> " ge ";
case IN -> " search.in";
case NIN -> " not search.in";
default -> throw new RuntimeException("Not supported expression type: " + exp.type());
};
}
@Override
public void doKey(Key key, StringBuilder context) {
var hasOuterQuotes = hasOuterQuotes(key.key());
var identifier = (hasOuterQuotes) ? removeOuterQuotes(key.key()) : key.key();
var prefixedIdentifier = withMetaPrefix(identifier);
if (hasOuterQuotes) {
prefixedIdentifier = "'" + prefixedIdentifier.trim() + "'";
}
context.append(prefixedIdentifier);
}
/**
* Adds the metadata field prefix to the given identifier name. Azure AI Search
* requires metadata fields to be prefixed with "meta_" to distinguish them from
* system fields.View on GitHub (pinned to 98a7beda4f)
Solutions
- Only pass comparison-type expressions (LT, LTE, GT, GTE, IN, NIN) to this converter; wrap AND/OR in Filter.and()/Filter.or() and let doExpression route them to doStartGroup/doEndGroup
- Upgrade spring-ai-azure-store and Spring AI core to matching versions so any new ExpressionType values are handled
- Catch RuntimeException around filter conversion and simplify the expression tree to only supported operators
- If you need an operator added, extend the switch in getOperationSymbol to map the missing type to its OData symbol
Example fix
// before
Expression e = new Expression(ExpressionType.GT, key, value);
String op = converter.getOperationSymbol(e); // ok only for comparisons
// after
Filter.ExpressionText text = new ExpressionText("year");
Filter.Expression e = GT(text, 2020); // build via Filter helper methods; convert whole tree with converter.convertExpression(expression) Defensive patterns
Strategy: try-catch
Validate before calling
private static final Set<ExpressionType> SUPPORTED = Set.of(ExpressionType.LT, ExpressionType.LTE, ExpressionType.GT, ExpressionType.GTE, ExpressionType.IN, ExpressionType.NIN);
if (expr instanceof Expression e && !SUPPORTED.contains(e.type())) { throw new IllegalArgumentException("Azure converter only supports comparison types, got: " + e.type()); } Type guard
boolean isAzureComparable(Filter.Operand o) { return o instanceof Expression e && Set.of(ExpressionType.LT, ExpressionType.LTE, ExpressionType.GT, ExpressionType.GTE, ExpressionType.IN, ExpressionType.NIN).contains(e.type()); } Try / catch
try { String filter = azureConverter.convertExpression(expression); ... } catch (RuntimeException e) { log.warn("Unsupported Azure filter expression: {}", e.getMessage()); /* fallback to unfiltered or client-side filtering */ } Prevention
- Build filters only via the Filter helper DSL so group types are routed through the group handlers
- Keep spring-ai-core and spring-ai-azure-store on aligned versions
- Restrict user-supplied filter queries to comparison operators
- Unit-test every ExpressionType your application emits against the converter
When it happens
Trigger: Calling the converter (directly or via AzureAiSearchVectorStore with similaritySearch(SearchRequest.builder().filterExpression(...))) with a Filter.Expression whose type() is not IN, NIN, LT, LTE, GT, or GTE — e.g. a raw Expression of type AND/OR/NOT that bypassed doExpression's normal grouping, or a newly added Filter.ExpressionType enum value in a newer Spring AI version not yet handled by this converter.
Common situations: Using a new Spring AI release that introduces new Filter.ExpressionType constants while the azure-store version is older; programmatically building Filter expressions and handing a group expression straight to getOperationSymbol instead of going through convertExpression/doExpression; custom subclasses calling getOperationSymbol directly.
Related errors
- Not allowed filter identifier name:
- Filter type not supported:
- Not supported expression type:
- Unsupported expression type:
- Not supported expression type:
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/535f3b237c3478de.
Report an issue: GitHub.