spring-projects/spring-ai · error · IllegalArgumentException
Expected a Value operand but got:
Error message
Expected a Value operand but got:
What it means
filterValue resolves the right side of a comparison and requires a Filter.Value operand holding the literal. A Filter.Key, Group, or nested Expression in the right-hand position throws IllegalArgumentException naming the actual operand class — the evaluator does not support field-to-field comparisons.
Source
Thrown at vector-stores/spring-ai-s3-vector-store/src/main/java/org/springframework/ai/vectorstore/s3/S3VectorStoreFilterExpressionEvaluator.java:116
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());
}
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());
}
private int compare(@Nullable Object metaVal, @Nullable Object filterVal) {
if (metaVal == null && filterVal == null) {
return 0;
}
if (metaVal == null) {
return -1;
}
if (filterVal == null) {
return 1;
}
if (metaVal instanceof Number n1 && filterVal instanceof Number n2) {
return Double.compare(n1.doubleValue(), n2.doubleValue());
}
if (Objects.equals(metaVal, filterVal)) {
return 0;
}View on GitHub (pinned to 98a7beda4f)
Solutions
- Use a literal Filter.Value on the right side; compute the comparison value in Java before filtering.
- For field-to-field logic, filter results client-side after similaritySearch instead of expressing it in the filter.
- Check operand construction: literals must be wrapped with new Filter.Value(x), field names with new Filter.Key("x").
- Use Filter.expr(...) to parse the filter string and get correct operand wrapping automatically.
Example fix
// before
new Filter.Expression(Filter.ExpressionType.EQ, new Filter.Key("status"), new Filter.Key("active"))
// after
new Filter.Expression(Filter.ExpressionType.EQ, new Filter.Key("status"), new Filter.Value("active")) Defensive patterns
Strategy: validation
Validate before calling
static void requireValueRight(Filter.Expression e) {
if (List.of(EQ, NE, GT, GTE, LT, LTE, IN, NIN).contains(e.type())
&& !(e.right() instanceof Filter.Value)) throw new IllegalStateException("Right side must be a literal Value");
} Type guard
static boolean isValueRight(Filter.Expression e) { return e.right() instanceof Filter.Value; } Try / catch
try { store.similaritySearch(req); } catch (IllegalArgumentException e) { if (e.getMessage().startsWith("Expected a Value operand")) { /* replace key-on-right with a computed literal */ } } Prevention
- Wrap literals in Filter.Value, field names in Filter.Key — check argument order at call sites.
- Field-to-field comparisons are unsupported; compute values in Java first.
- Use the string DSL (Filter.expr) to avoid operand wrapping mistakes.
When it happens
Trigger: Building a comparison whose right operand is another metadata key (field == field), or accidentally wrapping the literal in a Key instead of Value, then running S3VectorStore similaritySearch post-filtering.
Common situations: Attempts at field-to-field filters (e.g. createdAt == updatedAt) unsupported by S3 Vectors post-filter evaluation; constructor argument mix-ups; ports from stores that support key-on-right 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:
- Unsupported operand type:
- Expression of type %s requires a right operand
- Cannot compare values of incompatible types %s and %s
- Not supported expression type:
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/27d8437db9cc89e6.
Report an issue: GitHub.