spring-projects/spring-ai · error · IllegalArgumentException

Expected a List value for

Error message

Expected a List value for %s expression but got: %s

What it means

S3VectorStore's filter expression evaluator requires the operand of IN/NIN expressions to be a JSON array (List). When the right-hand operand of such a filter expression is any other type (a scalar, a string, a map), asList throws this IllegalArgumentException because the S3 vector store filter syntax can only express set membership against a list.

Solutions

  1. Wrap the operand in a List: use List.of(value) or a collection when constructing IN/NIN expressions.
  2. Validate the operand type (value instanceof List) before calling similaritySearch/delete with an IN/NIN expression.
  3. If a scalar equality was intended, use Filter.ExpressionType.EQ instead of IN.

Example fix

// before
var expr = new Filter.Expression(IN, new Key("country"), new Value("USA"));
// after
var expr = new Filter.Expression(IN, new Key("country"), new Value(List.of("USA", "UK")));
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(operand instanceof List<?> list)) { throw new IllegalArgumentException("IN/NIN operand must be a List"); }

Type guard

static boolean isListOperand(Object v) { return v instanceof List<?>; }

Try / catch

try { vectorStore.similaritySearch(request); } catch (IllegalArgumentException e) { if (e.getMessage().contains("Expected a List")) { /* rebuild expression with List operand */ } else throw e; }

Prevention

When it happens

Trigger: Calling S3VectorStore similaritySearch (or delete by filter) with a Filter.Expression of type IN or NIN whose right operand is not a java.util.List, e.g. new Filter.Expression(IN, key, new Value("usa")) instead of List.of("usa").

Common situations: Building filter expressions programmatically or from user input and passing a single value where a collection is expected; forgetting that IN/NIN must always take a collection operand; parsing a JSON filter where the value was deserialized as a String.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at vector-stores/spring-ai-s3-vector-store/src/main/java/org/springframework/ai/vectorstore/s3/S3VectorStoreFilterExpressionEvaluator.java:154

			try {
				@SuppressWarnings("unchecked")
				int result = comparable.compareTo(filterVal);
				return result;
			}
			catch (ClassCastException ex) {
				throw new IllegalArgumentException("Cannot compare values of incompatible types %s and %s"
					.formatted(metaVal.getClass().getName(), filterVal.getClass().getName()), ex);
			}
		}
		throw new IllegalArgumentException("Cannot compare values of types %s and %s"
			.formatted(metaVal.getClass().getName(), filterVal.getClass().getName()));
	}

	private List<?> asList(Object value, Filter.Expression expression) {
		if (value instanceof List<?> list) {
			return list;
		}
		throw new IllegalArgumentException(
				"Expected a List value for %s expression but got: %s".formatted(expression.type(), value));
	}

}

View on GitHub (pinned to 98a7beda4f)