spring-projects/spring-ai · error · RuntimeException
Not supported expression type:
Error message
Not supported expression type:
What it means
The Typesense filter expression converter maps each Filter.ExpressionType to a filter_by operator string. If the expression type falls outside the supported switch cases (AND, OR, EQ, NE, LT, LTE, GT, GTE, IN, NIN), getOperationSymbol throws a RuntimeException with 'Not supported expression type:'. Typesense's filter_by syntax cannot represent the unsupported operator.
Solutions
- Check which expression type you are passing and rewrite the filter using only supported operators (AND, OR, EQ, NE, LT, LTE, GT, GTE, IN, NIN).
- Upgrade or patch spring-ai-typesense-store if a newly added Filter.ExpressionType should be supported.
- Pre-validate expression types before calling the converter/store and reject unsupported ones with a clear error.
Example fix
// before
var expr = new Filter.Expression(Filter.ExpressionType.CONTAINS, new Key("title"), new Value("ai"));
// after
var expr = new Filter.Expression(Filter.ExpressionType.EQ, new Key("title"), new Value("ai")); Defensive patterns
Strategy: validation
Validate before calling
Set<Filter.ExpressionType> SUPPORTED = Set.of(AND, OR, EQ, NE, LT, LTE, GT, GTE, IN, NIN); if (!SUPPORTED.contains(expr.type())) throw new IllegalArgumentException("Typesense cannot filter on " + expr.type()); Try / catch
try { converter.convertExpression(expr); } catch (RuntimeException e) { if (e.getMessage().startsWith("Not supported expression type")) { /* fall back to in-memory filtering or another store */ } else throw e; } Prevention
- Restrict generated filters to the documented supported operators
- After Spring AI upgrades, re-check for new Filter.ExpressionType values
- Centralize filter construction so unsupported operators are rejected early
When it happens
Trigger: Passing a Filter.Expression with an operator Typesense doesn't map (currently none outside the standard set, but any new/unsupported type such as an unrecognized enum value reaches the default branch) via TypesenseVectorStore similaritySearch or the converter directly.
Common situations: Spring AI version upgrades introducing new Filter.ExpressionType values not yet handled by the converter; custom expression types from wrapper libraries; misuse of the converter API with hand-built expressions.
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
- Expression type not supported for numeric fields
- Expression type not yet implemented. Patches welcome.
- Not allowed filter identifier name:
- Not supported expression type:
- Not supported expression type
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/0895460339ad8a0e.
Report an issue: GitHub.
Appendix: source
Thrown at vector-stores/spring-ai-typesense-store/src/main/java/org/springframework/ai/vectorstore/typesense/TypesenseFilterExpressionConverter.java:52
this.convertOperand(exp.left(), context);
context.append(getOperationSymbol(exp));
this.convertOperand(exp.right(), context);
}
private String getOperationSymbol(Filter.Expression exp) {
return switch (exp.type()) {
case AND -> " && ";
case OR -> " || ";
case EQ -> " "; // in typesense "EQ" operator looks like -> country:USA
case NE -> " != ";
case LT -> " < ";
case LTE -> " <= ";
case GT -> " > ";
case GTE -> " >= ";
case IN -> " "; // in typesense "IN" operator looks like -> country: [USA, UK]
case NIN -> " != "; // in typesense "NIN" operator looks like -> country:
// !=[USA, UK]
default -> throw new RuntimeException("Not supported expression type:" + exp.type());
};
}
@Override
protected void doGroup(Filter.Group group, StringBuilder context) {
this.convertOperand(new Filter.Expression(Filter.ExpressionType.AND, group.content(), group.content()),
context); // trick
}
@Override
protected void doKey(Filter.Key key, StringBuilder context) {
var identifier = (hasOuterQuotes(key.key())) ? removeOuterQuotes(key.key()) : key.key();
// Typesense field names are bare identifiers in filter_by syntax
// (field_name:value) with no escaping mechanism. Validate that the
// identifier contains only safe characters to prevent filter injection.
for (int i = 0; i < identifier.length(); i++) {
char c = identifier.charAt(i);
if (!Character.isLetterOrDigit(c) && c != '_' && c != '.' && c != '-') {View on GitHub (pinned to 98a7beda4f)