spring-projects/spring-ai · error · IllegalArgumentException
Expression of type %s requires a left operand
Error message
Expression of type %s requires a left operand
What it means
SimpleVectorStoreFilterExpressionEvaluator's left() helper unwraps the left operand of a Filter.Expression. If the expression has no left operand, it throws IllegalArgumentException naming the expression type. This guards internal invariant violations when evaluating filter expressions like EQ, GT, AND, etc.
Source
Thrown at spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStoreFilterExpressionEvaluator.java:126
List<?> list = asList(filterValue(right(expression)), expression);
yield list.stream().anyMatch(item -> compare(metaVal, item) == 0);
}
case NIN -> {
Object metaVal = metadataValue(left(expression), metadata);
List<?> list = asList(filterValue(right(expression)), expression);
yield list.stream().noneMatch(item -> compare(metaVal, item) == 0);
}
// Unary operators: only the left operand (the key) is used.
// A non-null right operand is silently ignored here.
case ISNULL -> metadataValue(left(expression), metadata) == null;
case ISNOTNULL -> metadataValue(left(expression), metadata) != null;
};
}
private Filter.Operand left(Filter.Expression expression) {
Filter.Operand left = expression.left();
if (left == null) {
throw new IllegalArgumentException(
"Expression of type %s requires a left operand".formatted(expression.type()));
}
return left;
}
private Filter.Operand right(Filter.Expression expression) {
Filter.Operand right = expression.right();
if (right == null) {
throw new IllegalArgumentException(
"Expression of type %s requires a right operand".formatted(expression.type()));
}
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.View on GitHub (pinned to 98a7beda4f)
Solutions
- Build filter expressions with Filter.ExpressionBuilder or parse a string with FilterExpressionTextParser instead of constructing Filter.Expression manually.
- Ensure the left operand of every binary expression is a valid Filter.Key or nested Filter.Expression.
- Validate the expression tree before passing it to the vector store search.
Example fix
// before
new Filter.Expression(Filter.ExpressionType.EQ, null, new Filter.Value("green"));
// after
new Filter.Expression(Filter.ExpressionType.EQ, new Filter.Key("color"), new Filter.Value("green")); Defensive patterns
Strategy: validation
Validate before calling
boolean isWellFormed(Filter.Expression e) {
if (e == null) return false;
if (e.left() == null || e.right() == null) return false;
return true;
}
// call before passing expression to SearchRequest Type guard
boolean hasLeftOperand(Filter.Expression e) { return e != null && e.left() != null; } Try / catch
try {
vectorStore.similaritySearch(request);
} catch (IllegalArgumentException ex) {
if (ex.getMessage().contains("requires a left operand")) {
// rebuild expression via FilterExpressionTextParser
} else throw ex;
} Prevention
- Prefer FilterExpressionTextParser over manual Filter.Expression construction
- Never pass null operands when building Filter.Expression
When it happens
Trigger: Calling SimpleVectorStore.search or similaritySearch with a SearchRequest whose filter Expression was programmatically constructed (Filter.Expression) with a null left operand, e.g. new Filter.Expression(EQ, null, new Filter.Value(...)).
Common situations: Hand-building Filter.Expression trees instead of using FilterExpressionTextParser or FilterExpressionBuilder; NPE-prone custom DSL code; a Filter.Expression mutated or deserialized incorrectly.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Expression of type %s requires a right operand
- Expected a Key operand but got:
- Expected a Value operand but got:
- 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/7549133e2488e157.
Report an issue: GitHub.