spring-projects/spring-ai · error · IllegalArgumentException

Expected a List value for %s expression but got: %s

Error message

Expected a List value for %s expression but got: %s

What it means

IN and NIN expressions require the filter value to be a List. The evaluator's asList() throws IllegalArgumentException 'Expected a List value for %s expression but got: %s' when the right-hand operand of IN/NIN is a scalar value.

Source

Thrown at spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStoreFilterExpressionEvaluator.java:217

		}
		if (metaVal instanceof Comparable comparable && filterVal instanceof Comparable) {
			try {
				return comparable.compareTo(filterVal);
			}
			catch (ClassCastException ex) {
				throw new IllegalArgumentException("Cannot compare values of incompatible types %s and %s"
					.formatted(metaVal.getClass().getName(), filterVal.getClass().getName()), ex);
			}
		}
		throw new IllegalArgumentException("Cannot compare values of types %s and %s"
			.formatted(metaVal.getClass().getName(), filterVal.getClass().getName()));
	}

	private List<?> asList(Object value, Filter.Expression expression) {
		if (value instanceof List<?> list) {
			return list;
		}
		throw new IllegalArgumentException(
				"Expected a List value for %s expression but got: %s".formatted(expression.type(), value));
	}

}

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Wrap the value in java.util.List: new Filter.Value(List.of("US", "CA")).
  2. In text filters, use bracketed list syntax: country IN ['US','CA'].
  3. Guard collection-building code to always produce a List for IN/NIN operands, even for one element.

Example fix

// before
new Filter.Expression(IN, new Filter.Key("country"), new Filter.Value("US"));
// after
new Filter.Expression(IN, new Filter.Key("country"), new Filter.Value(List.of("US")));
Defensive patterns

Strategy: type-guard

Validate before calling

boolean isListValued(Filter.Expression e) {
    return e != null && e.right() instanceof Filter.Value v
        && v.value() instanceof java.util.List<?>;
}

Type guard

java.util.List<?> requireList(Filter.Value v) { return v.value() instanceof java.util.List<?> l ? l : java.util.List.of(); }

Try / catch

try {
    vectorStore.similaritySearch(request);
} catch (IllegalArgumentException ex) {
    if (ex.getMessage().contains("Expected a List value")) {
        // wrap scalar in List.of(...) and rebuild
    } else throw ex;
}

Prevention

When it happens

Trigger: Building new Filter.Expression(IN, new Filter.Key("country"), new Filter.Value("US")) — a scalar instead of List.of("US", "CA"); or a text filter like "country IN 'US'" missing brackets.

Common situations: Porting SQL IN clauses with a single element and dropping the list; dynamic filters built from a collection that collapsed to a single element; typos in filter string syntax.

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/87ca8faa6a31603d. Report an issue: GitHub.