spring-projects/spring-ai · error · IllegalArgumentException
Cannot compare values of incompatible types
Error message
Cannot compare values of incompatible types %s and %s
What it means
During comparison, if both metadata and filter values are Comparable but compareTo throws ClassCastException (e.g. comparing a String to an Integer), the evaluator wraps it in an IllegalArgumentException 'Cannot compare values of incompatible types'. Type mismatches between stored metadata and the filter literal cause this.
Solutions
- Make filter literal types match the stored metadata types (compare '2020' == '2020' or 2020 == 2020).
- Normalize metadata types at ingestion time (store numbers as numbers, dates as ISO strings).
- Catch IllegalArgumentException from search and log the offending metadata key/types.
Example fix
// before
// metadata: {"year": "2020"} filtered with
new Filter.Expression(GT, new Filter.Key("year"), new Filter.Value(2019));
// after
new Filter.Expression(GT, new Filter.Key("year"), new Filter.Value("2019")); // or store year as Integer Defensive patterns
Strategy: validation
Validate before calling
boolean typesMatch(Document doc, String key, Object literal) {
Object meta = doc.getMetadata().get(key);
return meta != null && literal != null
&& (meta.getClass().equals(literal.getClass())
|| (meta instanceof Number && literal instanceof Number));
} Try / catch
try {
vectorStore.similaritySearch(request);
} catch (IllegalArgumentException ex) {
if (ex.getMessage().startsWith("Cannot compare values of incompatible types")) {
// fix literal type or normalize metadata and retry
} else throw ex;
} Prevention
- Enforce consistent metadata types at ingestion time
- Quote string literals in text filters to avoid numeric coercion mismatches
When it happens
Trigger: Metadata stored as "2020" (String) filtered with year == 2020 (Integer), or metadata as Integer filtered with a String literal — numeric promotion succeeds for numbers, but mixed String/Number types fall through to Comparable.compareTo and fail.
Common situations: Documents ingested by one pipeline writing String metadata while the filter uses numeric literals (JSON query strings parse numbers as Integer/Double); mixed ingestion formats.
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
- Cannot compare values of types
- Cannot compare values of types
- Expected a List value for
- Cannot compare values of incompatible types
- Expected a Key operand but got:
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/0acc6d12fbe94238.
Report an issue: GitHub.
Appendix: source
Thrown at spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStoreFilterExpressionEvaluator.java:205
}
if (metaVal == null) {
return -1;
}
if (filterVal == null) {
return 1;
}
if (metaVal instanceof Number n1 && filterVal instanceof Number n2) {
return Double.compare(n1.doubleValue(), n2.doubleValue());
}
if (Objects.equals(metaVal, filterVal)) {
return 0;
}
if (metaVal instanceof Comparable comparable && filterVal instanceof Comparable) {
try {
return comparable.compareTo(filterVal);
}
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)