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

  1. Apply NOT only to group or comparison expressions (NOT(AND(...)), NOT(GT(...)), NOT(IN(...))) rather than bare values
  2. Rewrite the filter manually: replace NOT(X) with the logically inverted expression using supported operators
  3. Ensure Spring AI core and the Bedrock store versions are aligned so FilterHelper.negate behaves as expected
  4. 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

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


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/aa0d1866edaec013. Report an issue: GitHub.