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

  1. Only pass leaf comparison expressions (EQ, NE, GT, GTE, LT, LTE, IN, NIN) to negate(); destructure AND/OR yourself and negate each branch
  2. Handle NOT by dropping the outer NOT instead of calling negate on a NOT node (double negation)
  3. Handle ISNULL/ISNOTNULL negation yourself before delegating to negate()
  4. 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

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


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)