spring-projects/spring-ai · error · UnsupportedOperationException
Unsupported operator:
Error message
Unsupported operator:
What it means
convertExpression throws UnsupportedOperationException when the top-level expression type is not one of EQ/NE/GTE/GT/LTE/LT, IN/NIN, or AND/OR. In practice this fires for NOT (and any other unmapped type): NOT has a symbol in getOperationSymbol but no case in convertExpression's switch, so it reaches the default branch.
Source
Thrown at vector-stores/spring-ai-s3-vector-store/src/main/java/org/springframework/ai/vectorstore/s3/S3VectorFilterSearchExpressionConverter.java:89
case LTE:
case LT:
return Document.fromMap(Map.of(((Filter.Key) expression.left()).key(), Document
.fromMap(Map.of(operationType, wrapValue(Objects.requireNonNull(expression.right()))))));
case IN:
case NIN:
Document document = wrapValue(Objects.requireNonNull(expression.right()));
return Document.fromMap(Map.of(((Filter.Key) expression.left()).key(),
Document.fromMap(Map.of(operationType, document))));
case AND:
case OR:
Document leftDocument = wrapValue(Objects.requireNonNull(expression.left()));
Document rightDocument = wrapValue(Objects.requireNonNull(expression.right()));
return Document.fromMap(Map.of(operationType, Document.fromList(List.of(leftDocument, rightDocument))));
default:
throw new UnsupportedOperationException("Unsupported operator: " + expression.type());
}
}
private Document wrapValue(Filter.Operand operand) {
if (operand instanceof Filter.Value) {
return convertToDocument(((Filter.Value) operand).value());
}
else if (operand instanceof Filter.Key) {
return Document.fromString(((Filter.Key) operand).key());
}
else if (operand instanceof Filter.Group) {
Filter.Expression expression = ((Filter.Group) operand).content();
return convertExpression(expression);
}
else {
return convertExpression((Filter.Expression) operand);
}
}View on GitHub (pinned to 98a7beda4f)
Solutions
- Avoid NOT at the top level or inside filters; rewrite using De Morgan's law, e.g. NOT(A AND B) -> (!A) OR (!B) expressed with NE/NIN where possible.
- Negate in Java instead: run the search with the positive predicate and filter out results client-side.
- Upgrade Spring AI in case a newer version adds a NOT case to convertExpression.
- Wrap the converter or contribute a NOT branch that wraps the child expression in a {"$not": ...} Document.
Example fix
// before
new Filter.Expression(Filter.ExpressionType.NOT, Filter.group(eq("category", "x")), null)
// after
new Filter.Expression(Filter.ExpressionType.NE, new Filter.Key("category"), new Filter.Value("x")) Defensive patterns
Strategy: validation
Validate before calling
private static void assertNoNot(Filter.Expression e) {
if (e.type() == Filter.ExpressionType.NOT) throw new IllegalArgumentException("NOT not supported by S3 converter");
if (e.left() instanceof Filter.Expression l) assertNoNot(l);
if (e.right() instanceof Filter.Expression r) assertNoNot(r);
} Type guard
static boolean isRewritable(Filter.ExpressionType t) { return t != Filter.ExpressionType.NOT; } Try / catch
try { store.similaritySearch(req); } catch (UnsupportedOperationException e) { /* fall back to unfiltered search + client-side NOT filter */ } Prevention
- Never emit NOT at any level of filters sent to S3VectorStore; rewrite with NE/NIN.
- Negate results in application code rather than in the filter expression.
- Track converter switch coverage when new Spring AI filter operators are introduced.
When it happens
Trigger: Passing a filter containing a NOT expression (e.g. new Filter.Expression(NOT, group, null)) to S3VectorStore.similaritySearch; this always throws because convertExpression has no NOT case, despite getOperationSymbol mapping it to $not.
Common situations: Building filters like NOT(category = 'x') against the S3 vector store; migrating queries from other Spring AI vector stores where NOT works; library gap where NOT is half-supported.
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
- Not supported expression type:
- Expression of type %s requires a left operand
- Not supported expression type:
- Unsupported Number type:
- Unsupported operand type:
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/3b035492e13ac76d.
Report an issue: GitHub.