spring-projects/spring-ai · error · IllegalArgumentException
Expected a Key operand but got:
Error message
Expected a Key operand but got:
What it means
The evaluator's metadataValue() expects the left operand of a comparison to be a Filter.Key naming a metadata field. If the operand is a Value (or any other Operand type), it throws IllegalArgumentException including the actual class name. Metadata comparisons must be keyed on document metadata, not constants on the left side.
Source
Thrown at spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStoreFilterExpressionEvaluator.java:155
}
return right;
}
/**
* Extracts the metadata value for the given {@link Filter.Key} operand. Outer quotes
* ({@code "..."} or {@code '...'}) are stripped from the key name to match the format
* used by {@link FilterExpressionBuilder} and the text parser.
*/
private @Nullable Object metadataValue(Filter.Operand operand, Map<String, Object> metadata) {
if (operand instanceof Filter.Key key) {
String k = key.key();
if (k.length() >= 2
&& ((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 otherView on GitHub (pinned to 98a7beda4f)
Solutions
- Make the metadata field a Filter.Key on the left side and the constant a Filter.Value on the right.
- If using the text parser, write the filter as 'color == \'green\'' not '\'green\' == color'.
- Inspect the parsed expression tree (Filter.Expression#left) to confirm the left operand is a Key.
Example fix
// before
new Filter.Expression(EQ, new Filter.Value("green"), new Filter.Key("color"));
// after
new Filter.Expression(EQ, new Filter.Key("color"), new Filter.Value("green")); Defensive patterns
Strategy: validation
Validate before calling
boolean leftIsKey(Filter.Expression e) {
return e != null && e.left() instanceof Filter.Key;
} Type guard
Filter.Key asKey(Filter.Operand op) { return op instanceof Filter.Key k ? k : null; } Try / catch
try {
vectorStore.similaritySearch(request);
} catch (IllegalArgumentException ex) {
if (ex.getMessage().startsWith("Expected a Key operand")) {
// swap operands: metadata key must be on the left
} else throw ex;
} Prevention
- Write text filters as field == value, never value == field
- In builder code, put Filter.Key first and Filter.Value second
When it happens
Trigger: A Filter.Expression like EQ(value, value) or EQ(value, key) — i.e. a Filter.Value used where a Filter.Key is expected — evaluated against SimpleVectorStore.
Common situations: Swapping operand order when hand-building expressions; string filters like "'green' == color" instead of "color == 'green'"; code generation producing reversed 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 Value 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/878589c6fae86745.
Report an issue: GitHub.