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

  1. Build filter expressions with Filter.ExpressionBuilder or parse a string with FilterExpressionTextParser instead of constructing Filter.Expression manually.
  2. Ensure the left operand of every binary expression is a valid Filter.Key or nested Filter.Expression.
  3. 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

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


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/7549133e2488e157. Report an issue: GitHub.