spring-projects/spring-ai · error · IllegalArgumentException
Unknown expression type:
Error message
Unknown expression type:
What it means
FilterHelper.negate computes the negation (NOT) of an expression by flipping its type via TYPE_NEGATION_MAP (GT<->LTE, EQ<->NE, IN<->NIN, etc.). If the expression's type has no entry in the map (e.g. AND/OR/NOT, or an unsupported type) it throws IllegalArgumentException("Unknown expression type: " + type).
Solutions
- Only pass leaf comparison expressions (EQ, NE, GT, GTE, LT, LTE, IN, NIN) to negate(); destructure AND/OR yourself and negate each branch
- Handle NOT by dropping the outer NOT instead of calling negate on a NOT node (double negation)
- Handle ISNULL/ISNOTNULL negation yourself before delegating to negate()
- Catch IllegalArgumentException and fall back to emitting an explicit NOT(...) expression
Example fix
// before Filter.Expression n = FilterHelper.negate(andExpr); // throws // after Filter.Expression n = new Filter.Expression(ExpressionType.NOT, andExpr); // or negate each leaf
Defensive patterns
Strategy: type-guard
Type guard
boolean isNegatable(Filter.Expression e) { return Set.of(ExpressionType.EQ, ExpressionType.NE, ExpressionType.GT, ExpressionType.GTE, ExpressionType.LT, ExpressionType.LTE, ExpressionType.IN, ExpressionType.NIN).contains(e.type()); } Try / catch
try { return FilterHelper.negate(exp); }
catch (IllegalArgumentException e) { return new Filter.Expression(ExpressionType.NOT, exp); } Prevention
- Only negate leaf comparison expressions
- Push NOT through AND/OR yourself (De Morgan) before negating leaves
When it happens
Trigger: Calling FilterHelper.negate() directly (or via inEx in expandIn/expandNin pipelines) with a Filter.Expression whose type() is not a simple comparison, such as NOT, AND, OR, or another type absent from TYPE_NEGATION_MAP.
Common situations: Custom vector-store code that reuses FilterHelper to push NOT down into provider-specific query languages; passing a compound expression where a leaf comparison was expected.
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
- Can not negate operand of type:
- Cannot compare values of incompatible types
- Cannot compare values of incompatible types
- Cannot compare values of types
- Cannot compare values of types
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/6101658320e7e3e1.
Report an issue: GitHub.
Appendix: source
Thrown at spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/FilterHelper.java:98
switch (exp.type()) {
case NOT: // NOT(NOT(a)) = a
return negate(exp.left());
case AND: // NOT(a AND b) = NOT(a) OR NOT(b)
case OR: // NOT(a OR b) = NOT(a) AND NOT(b)
return new Filter.Expression(TYPE_NEGATION_MAP.get(exp.type()), negate(exp.left()),
negate(exp.right()));
case EQ: // NOT(e EQ b) = e NE b
case NE: // NOT(e NE b) = e EQ b
case GT: // NOT(e GT b) = e LTE b
case GTE: // NOT(e GTE b) = e LT b
case LT: // NOT(e LT b) = e GTE b
case LTE: // NOT(e LTE b) = e GT b
return new Filter.Expression(TYPE_NEGATION_MAP.get(exp.type()), exp.left(), exp.right());
case IN: // NOT(e IN [...]) = e NIN [...]
case NIN: // NOT(e NIN [...]) = e IN [...]
return new Filter.Expression(TYPE_NEGATION_MAP.get(exp.type()), exp.left(), exp.right());
default:
throw new IllegalArgumentException("Unknown expression type: " + exp.type());
}
}
else {
throw new IllegalArgumentException("Can not negate operand of type: " + operand.getClass());
}
}
/**
* Expands the IN into a semantically equivalent boolean expressions of ORs of EQs.
* Useful for providers that don't provide native IN support.
*
* For example the <pre>
* foo IN ["bar1", "bar2", "bar3"]
* </pre>
*
* expression is equivalent to
*
* <pre>View on GitHub (pinned to 98a7beda4f)