spring-projects/spring-ai · error · IllegalArgumentException
NOT operator negation failed for expression type: . Operand:
Error message
NOT operator negation failed for expression type: . Operand:
What it means
convertNot uses FilterHelper.negate(expression) to turn NOT X into a directly expressible form; if negation returns a plain Value operand rather than an Expression (e.g. negating something the helper cannot structurally invert), the converter cannot recurse and throws an IllegalArgumentException describing the original type and operand. This is an internal invariant guard within NOT handling.
Source
Thrown at vector-stores/spring-ai-bedrock-knowledgebase-store/src/main/java/org/springframework/ai/vectorstore/bedrockknowledgebase/BedrockKnowledgeBaseFilterExpressionConverter.java:91
RetrievalFilter left = convert(asExpression(leftOp));
RetrievalFilter right = convert(asExpression(rightOp));
return RetrievalFilter.builder().andAll(left, right).build();
}
private RetrievalFilter convertOr(final Expression expression) {
Filter.Operand leftOp = Objects.requireNonNull(expression.left(), "left operand");
Filter.Operand rightOp = Objects.requireNonNull(expression.right(), "right operand");
RetrievalFilter left = convert(asExpression(leftOp));
RetrievalFilter right = convert(asExpression(rightOp));
return RetrievalFilter.builder().orAll(left, right).build();
}
private RetrievalFilter convertNot(final Expression expression) {
Filter.Operand negated = FilterHelper.negate(expression);
if (negated instanceof Expression negatedExpr) {
return convert(negatedExpr);
}
throw new IllegalArgumentException(
"NOT operator negation failed for expression type: " + expression.type() + ". Operand: " + negated);
}
private RetrievalFilter buildComparison(final Expression exp, final ComparisonOp op) {
Filter.Operand leftOp = Objects.requireNonNull(exp.left(), "left operand");
Filter.Operand rightOp = Objects.requireNonNull(exp.right(), "right operand");
String key = ((Key) leftOp).key();
Object value = extractValue(rightOp);
FilterAttribute attr = createFilterAttribute(key, value);
return switch (op) {
case EQ -> RetrievalFilter.builder().equalsValue(attr).build();
case NE -> RetrievalFilter.builder().notEquals(attr).build();
case GT -> RetrievalFilter.builder().greaterThan(attr).build();
case GTE -> RetrievalFilter.builder().greaterThanOrEquals(attr).build();
case LT -> RetrievalFilter.builder().lessThan(attr).build();
case LTE -> RetrievalFilter.builder().lessThanOrEquals(attr).build();
};View on GitHub (pinned to 98a7beda4f)
Solutions
- Apply NOT only to group or comparison expressions (NOT(AND(...)), NOT(GT(...)), NOT(IN(...))) rather than bare values
- Rewrite the filter manually: replace NOT(X) with the logically inverted expression using supported operators
- Ensure Spring AI core and the Bedrock store versions are aligned so FilterHelper.negate behaves as expected
- Catch IllegalArgumentException from similaritySearch and fall back to no-filter search plus client-side filtering
Example fix
// before
Expression e = NOT(new Value(true)); // negation yields a Value, not Expression
// after
Expression e = EQ(new ExpressionText("flag"), false); // express the intent directly without NOT Defensive patterns
Strategy: validation
Validate before calling
if (expr.type() == ExpressionType.NOT) { Filter.Operand inner = expr.left(); if (!(inner instanceof Expression)) { throw new IllegalArgumentException("NOT must wrap a sub-expression, got: " + inner); } } Type guard
boolean notWrapsExpression(Filter.Operand o) { return o instanceof Expression e && e.type() != ExpressionType.NOT || (e != null && e.left() instanceof Expression); } Try / catch
try { String filter = converter.convertExpression(expression); ... } catch (IllegalArgumentException e) { log.warn("NOT negation failed: {}", e.getMessage()); /* rewrite or drop the NOT */ } Prevention
- Only wrap AND/OR/comparison expressions in NOT
- Manually invert filters instead of relying on NOT when possible
- Keep Spring AI core aligned with the Bedrock store version so FilterHelper.negate behaves consistently
- Test NOT-containing filters against the converter in unit tests
When it happens
Trigger: Converting a filter like NOT(value) or NOT(IN(...)) whose negation by FilterHelper yields a non-Expression operand (e.g. a boolean Value) instead of an invertible sub-expression, via BedrockKnowledgeBaseVectorStore.similaritySearch with such a filterExpression or direct convertNot call.
Common situations: Wrapping a bare value or unsupported leaf in NOT(); library version mismatch where FilterHelper.negate changed return behavior; hand-built expression trees with NOT around operands that are not AND/OR/comparison expressions.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Filter type not supported:
- Expected Expression but got:
- Expected Value but got:
- Expected List for IN/NIN but got:
- The region '<region>' is not a valid region!
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/aa0d1866edaec013.
Report an issue: GitHub.