spring-projects/spring-ai · error · IllegalArgumentException
Expected a Value operand but got:
Error message
Expected a Value operand but got:
What it means
The evaluator's filterValue() expects the right operand of a comparison to be a Filter.Value holding a constant. If it receives a Key (or another Operand type), it throws IllegalArgumentException with the operand's class name. The right side of a comparison must be a literal value, not a metadata key.
Source
Thrown at spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStoreFilterExpressionEvaluator.java:168
&& ((k.startsWith("\"") && k.endsWith("\"")) || (k.startsWith("'") && k.endsWith("'")))) {
k = k.substring(1, k.length() - 1);
}
return metadata.get(k);
}
throw new IllegalArgumentException("Expected a Key operand but got: " + operand.getClass().getName());
}
/**
* Extracts the constant value from a {@link Filter.Value} operand. {@link Date}
* instances are formatted to their ISO-8601 UTC string so they can be compared
* directly with metadata strings stored in the same format.
*/
private Object filterValue(Filter.Operand operand) {
if (operand instanceof Filter.Value filterValue) {
Object value = filterValue.value();
return (value instanceof Date date) ? DATE_FORMATTER.format(date.toInstant()) : value;
}
throw new IllegalArgumentException("Expected a Value operand but got: " + operand.getClass().getName());
}
/**
* Compares two values. Numbers are promoted to {@code double} to allow cross-type
* numeric comparison (e.g. {@code Integer} vs {@code Double}). All other
* {@link Comparable} types are compared directly.
*
* <p>
* Null ordering follows SQL {@code NULLS FIRST} semantics: {@code null} is considered
* less than any non-null value. As a result, a missing metadata key causes ordered
* comparisons ({@code GT}, {@code GTE}, {@code LT}, {@code LTE}) to behave as if the
* key holds the smallest possible value — e.g. {@code year > 2020} returns
* {@code false} when {@code year} is absent.
*/
@SuppressWarnings("unchecked")
private int compare(@Nullable Object metaVal, @Nullable Object filterVal) {
if (metaVal == null && filterVal == null) {
return 0;View on GitHub (pinned to 98a7beda4f)
Solutions
- Wrap the constant in a Filter.Value on the right side of the expression.
- Cross-field metadata comparison is unsupported — compute the comparison before building the filter.
- Verify the parsed expression's right operand is a Filter.Value before search.
Example fix
// before
new Filter.Expression(EQ, new Filter.Key("color"), new Filter.Key("shade"));
// after
new Filter.Expression(EQ, new Filter.Key("color"), new Filter.Value("shade")); Defensive patterns
Strategy: validation
Validate before calling
boolean rightIsValue(Filter.Expression e) {
return e != null && e.right() instanceof Filter.Value;
} Type guard
Filter.Value asValue(Filter.Operand op) { return op instanceof Filter.Value v ? v : null; } Try / catch
try {
vectorStore.similaritySearch(request);
} catch (IllegalArgumentException ex) {
if (ex.getMessage().startsWith("Expected a Value operand")) {
// wrap the right operand's constant in Filter.Value
} else throw ex;
} Prevention
- Never compare two metadata keys; cross-field comparison is unsupported
- Always construct constants as new Filter.Value(...)
When it happens
Trigger: A Filter.Expression like EQ(key, key) — two metadata keys compared — evaluated by SimpleVectorStore; nested Filter.Expression where a Value was expected.
Common situations: Hand-building expressions comparing two metadata fields; forgetting to wrap the constant in Filter.Value; translating SQL-style key-to-key comparisons.
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
- Expected a Key operand but got:
- Expression of type %s requires a left operand
- Expression of type %s requires a right operand
- Cannot compare values of incompatible types %s and %s
- Cannot compare values of types %s and %s
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/0f4a9fb1ba8d4f82.
Report an issue: GitHub.