spring-projects/spring-ai · error · IllegalArgumentException

Expected a List, but got:

Error message

Expected a List, but got: 

What it means

PgVectorFilterExpressionConverter.convertToConditions only supports IN/NOTIN (NIN) filter expressions whose right operand is a Filter.Value wrapping a java.util.List. If the right side is a single value (e.g. Filter.eq-style value passed where an IN was expected, or a non-collection value), the cast to List would fail, so the converter throws this IllegalArgumentException up front.

Source

Thrown at vector-stores/spring-ai-pgvector-store/src/main/java/org/springframework/ai/vectorstore/pgvector/PgVectorFilterExpressionConverter.java:83

		else {
			this.convertOperand(expression.left(), context);
			context.append(getOperationSymbol(expression));
			this.convertOperand(expression.right(), context);
		}
	}

	private void handleIn(Expression expression, StringBuilder context) {
		context.append("(");
		convertToConditions(expression, context);
		context.append(")");
	}

	private void convertToConditions(Expression expression, StringBuilder context) {
		Assert.state(expression.right() != null, "expression should have a right operand");
		Filter.Value right = (Filter.Value) expression.right();
		Object value = right.value();
		if (!(value instanceof List)) {
			throw new IllegalArgumentException("Expected a List, but got: " + value.getClass().getSimpleName());
		}
		List<Object> values = (List) value;
		for (int i = 0; i < values.size(); i++) {
			this.convertOperand(expression.left(), context);
			context.append(" == ");
			this.doSingleValue(normalizeDateString(values.get(i)), context);
			if (i < values.size() - 1) {
				context.append(" || ");
			}
		}
	}

	private void handleNotIn(Expression expression, StringBuilder context) {
		context.append("!(");
		convertToConditions(expression, context);
		context.append(")");
	}

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Wrap the right-hand operand in a List: Filter.in("country", List.of("US","DE")) instead of a single value.
  2. Use Filter.eq / Filter.ne for single-value comparisons instead of in/nin.
  3. Check the Filter.Expression you built: expression.right() must be a Filter.Value whose value() instanceof List.

Example fix

// before
Expression e = new Expression(IN, "country", new Value("US"));
// after
Expression e = new Expression(IN, "country", new Value(List.of("US", "DE")));
Defensive patterns

Strategy: validation

Validate before calling

if (!(expr instanceof Filter.Expression fe && fe.right() instanceof Filter.Value v && v.value() instanceof List)) {
    throw new IllegalArgumentException("IN/NIN requires a List value");
}

Type guard

static boolean isInWithListValue(Expression e) {
    return e instanceof Filter.Expression fe
        && fe.right() instanceof Filter.Value v
        && v.value() instanceof List<?>;
}

Try / catch

try {
    String sql = converter.convertExpression(expr);
} catch (IllegalArgumentException e) {
    // log offending expression; fix filter construction
}

Prevention

When it happens

Trigger: Building a PgVectorStore filter like Filter.in("country", ...) indirectly but with a single non-List value on the right side — e.g. using Filter.in with a scalar, or a custom Expression whose right() is a Value holding a String/Number instead of a List.

Common situations: Hand-constructing Filter.Expression trees instead of using the Filter expression DSL; migrating filters from another vector store whose converter accepted scalars for IN; a typo where eq was intended but in semantics got built.

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/5f0e997527efd559. Report an issue: GitHub.