spring-projects/spring-ai · error · IllegalArgumentException
Expression of type %s requires a right operand
Error message
Expression of type %s requires a right operand
What it means
The evaluator's right() accessor throws IllegalArgumentException when a Filter.Expression lacks a right operand where one is required. Binary operators (AND, OR, EQ, NE, GT, GTE, LT, LTE, IN, NIN) all dereference right(), so a null right operand is rejected as a malformed filter.
Source
Thrown at vector-stores/spring-ai-s3-vector-store/src/main/java/org/springframework/ai/vectorstore/s3/S3VectorStoreFilterExpressionEvaluator.java:93
}
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;
}
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) {View on GitHub (pinned to 98a7beda4f)
Solutions
- Always supply a Filter.Value for comparison operators; use the string "null" sentinel or a dedicated metadata flag if you mean 'missing'.
- For null checks use ISNULL/ISNOTNULL expression types, which do not require a right operand.
- Skip building the expression entirely when the value is absent, rather than passing null.
- Validate the filter tree (all binary nodes have both operands) before calling similaritySearch.
Example fix
// before
new Filter.Expression(Filter.ExpressionType.EQ, new Filter.Key("genre"), null)
// after
new Filter.Expression(Filter.ExpressionType.ISNULL, new Filter.Key("genre"), null) Defensive patterns
Strategy: validation
Validate before calling
static boolean needsRight(Filter.ExpressionType t) { return t != NOT && t != ISNULL && t != ISNOTNULL; }
static void requireRight(Filter.Expression e) { if (needsRight(e.type()) && e.right() == null) throw new IllegalStateException("Missing right operand"); } Type guard
static boolean hasRight(Filter.Expression e) { return e.right() != null; } Try / catch
try { store.similaritySearch(req); } catch (IllegalArgumentException e) { if (e.getMessage().endsWith("requires a right operand")) { /* drop or rebuild the incomplete predicate */ } } Prevention
- Skip building predicates whose value is null; use ISNULL/ISNOTNULL for missing-field checks.
- Guard dynamic filter builders: never pass null as a right operand for binary operators.
- Validate the complete filter tree before similaritySearch.
When it happens
Trigger: Building a comparison like new Filter.Expression(EQ, new Filter.Key("genre"), null) or a binary AND/OR missing its second child, then running S3VectorStore similaritySearch that evaluates the filter against ListVectors metadata.
Common situations: Partial filter assembly (value forgotten); ISNULL/ISNOTNULL-style expressions ported from other stores where the right side is null by convention — here ISNULL/ISNOTNULL read only the left side, but comparisons with null right side throw; dynamic filter builders that skip unset values.
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
- Unsupported operand type:
- Expression of type %s requires a left operand
- Expected a Key operand but got:
- Expected a Value operand but got:
- Cannot compare values of incompatible types %s and %s
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/f603bfd5ac31d48e.
Report an issue: GitHub.