spring-projects/spring-ai · error · IllegalStateException

Filter IN right expression should be of Filter.Value type…

Error message

Filter IN right expression should be of Filter.Value type but was 

What it means

expandInNinExpressions expands IN/NIN expressions into OR/AND trees of EQ/NE comparisons so providers without native IN can evaluate them. The right side of an IN must be a Filter.Value containing the collection; if exp.right() is non-null but not a Filter.Value, it throws IllegalStateException("Filter IN right expression should be of Filter.Value type but was " + class).

Solutions

  1. Set the right side of IN/NIN to a Filter.Value holding the collection, e.g. new Filter.Value(List.of("red","green"))
  2. Add a validation step on your filter tree before conversion: right() of IN/NIN must be Filter.Value
  3. Catch IllegalStateException from the converter and report the misbuilt expression

Example fix

// before
new Filter.Expression(ExpressionType.IN, new Filter.Key("color"), new Filter.Key("colors"));
// after
new Filter.Expression(ExpressionType.IN, new Filter.Key("color"), new Filter.Value(List.of("red", "green")));
Defensive patterns

Strategy: validation

Validate before calling

Assert.isTrue(exp.type() != ExpressionType.IN && exp.type() != ExpressionType.NIN || exp.right() instanceof Filter.Value, "IN/NIN right side must be Filter.Value");

Type guard

boolean hasValueRight(Filter.Expression e) { return e.right() instanceof Filter.Value; }

Try / catch

try { converted = converter.convertExpression(exp); }
catch (IllegalStateException e) { throw new IllegalArgumentException("Malformed IN expression: " + e.getMessage(), e); }

Prevention

When it happens

Trigger: Building a Filter.Expression with type IN or NIN whose right() is another Filter.Expression or plain operand (e.g. new Filter.Expression(IN, key, someExpression)), then converting via a converter that calls expandIn/expandNin.

Common situations: Hand-constructed filter trees where the author put a nested expression instead of a Value list on the right of IN; code generators producing wrong operand types.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/FilterHelper.java:184

				// foo != "bar2" && foo != "bar3"
				// or equivalent to AND(foo != "bar1" AND( foo != "bar2" OR(foo !=
				// "bar3")))
				List<Filter.Expression> eqExprs = new ArrayList<>();
				for (Object o : list) {
					eqExprs.add(new Filter.Expression(innerExpressionType, exp.left(), new Filter.Value(o)));
				}
				context.append(expressionConverter.convertExpression(aggregate(outerExpressionType, eqExprs)));
			}
			else {
				// 1. foo IN ["bar"] is equivalent to foo == "BAR"
				// 2. foo NIN ["bar"] is equivalent to foo != "BAR"
				context.append(expressionConverter
					.convertExpression(new Filter.Expression(innerExpressionType, exp.left(), exp.right())));
			}
		}
		else {
			Assert.state(exp.right() != null, "Filter IN right expression was null");
			throw new IllegalStateException(
					"Filter IN right expression should be of Filter.Value type but was " + exp.right().getClass());
		}
	}

	/**
	 * Recursively aggregates a list of expression into a binary tree with 'aggregateType'
	 * join nodes.
	 * @param aggregateType type all tree splits.
	 * @param expressions list of expressions to aggregate.
	 * @return Returns a binary tree expression.
	 */
	private static Filter.Expression aggregate(Filter.ExpressionType aggregateType,
			List<Filter.Expression> expressions) {

		if (expressions.size() == 1) {
			return expressions.get(0);
		}
		return new Filter.Expression(aggregateType, expressions.get(0),

View on GitHub (pinned to 98a7beda4f)