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

SimpleVectorStoreFilterExpressionEvaluator's right() helper unwraps the right operand of a Filter.Expression. If the right operand is null, it throws IllegalArgumentException naming the expression type. Binary filter expressions (EQ, IN, AND, OR, comparisons) all require a right operand.

Source

Thrown at spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStoreFilterExpressionEvaluator.java:135

			// 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.
	 */
	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);

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Always supply a Filter.Value (or nested Filter.Expression) as the right operand when building Filter.Expression instances.
  2. Use FilterExpressionTextParser to parse filter strings, which guarantees well-formed operands.
  3. Null-check operands in any custom expression-building code before search.

Example fix

// before
new Filter.Expression(Filter.ExpressionType.GT, new Filter.Key("year"), null);
// after
new Filter.Expression(Filter.ExpressionType.GT, new Filter.Key("year"), new Filter.Value(2020));
Defensive patterns

Strategy: validation

Validate before calling

boolean isWellFormed(Filter.Expression e) {
    return e != null && e.left() != null && e.right() != null;
}

Type guard

boolean hasRightOperand(Filter.Expression e) { return e != null && e.right() != null; }

Try / catch

try {
    vectorStore.similaritySearch(request);
} catch (IllegalArgumentException ex) {
    if (ex.getMessage().contains("requires a right operand")) {
        // supply the missing Filter.Value and retry build
    } else throw ex;
}

Prevention

When it happens

Trigger: Passing a programmatically constructed Filter.Expression with null right operand into a SearchRequest filter, e.g. new Filter.Expression(GT, new Filter.Key("year"), null).

Common situations: Manual Filter.Expression construction where the value operand was forgotten; deserialization dropping the right side; builder code with a conditional value path that returns null.

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/28782daa3f0557d6. Report an issue: GitHub.