spring-projects/spring-ai · error · IllegalArgumentException
Cannot compare values of incompatible types %s and %s
Error message
Cannot compare values of incompatible types %s and %s
What it means
compare() throws this when both metadata and filter values are Comparable but compareTo() raises ClassCastException, e.g. comparing a String metadata value against a numeric filter value. It is the evaluator's way of surfacing mixed-type comparisons during post-filtering of ListVectors metadata.
Source
Thrown at vector-stores/spring-ai-s3-vector-store/src/main/java/org/springframework/ai/vectorstore/s3/S3VectorStoreFilterExpressionEvaluator.java:142
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 {
@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)
Solutions
- Match the filter literal type to the stored metadata type (e.g. Filter.Value("30") for String metadata).
- Fix the ingestion pipeline so the field is always written with a consistent type across documents.
- Normalize values before filtering: convert metadata or filter values to a common type (Number or ISO date String).
- For dates, remember the evaluator formats Date filter values as yyyy-MM-dd'T'HH:mm:ss'Z' strings — compare against same-format string metadata, or pre-convert.
Example fix
// before
new Filter.Expression(Filter.ExpressionType.GT, new Filter.Key("age"), new Filter.Value(30)) // metadata age is "30" String
// after
new Filter.Expression(Filter.ExpressionType.GT, new Filter.Key("age"), new Filter.Value("30")) Defensive patterns
Strategy: validation
Validate before calling
static void assertSameScalarType(Object metadataSample, Object filterValue) {
if (metadataSample != null && !metadataSample.getClass().isInstance(filterValue)
&& !(metadataSample instanceof Number && filterValue instanceof Number))
throw new IllegalStateException("Filter type " + filterValue.getClass() + " differs from metadata type " + metadataSample.getClass());
} Type guard
static boolean comparableTypes(Object a, Object b) { return (a instanceof Number && b instanceof Number) || (a != null && b != null && a.getClass().equals(b.getClass())); } Try / catch
try { store.similaritySearch(req); } catch (IllegalArgumentException e) { if (e.getMessage().startsWith("Cannot compare values of incompatible types")) { /* rebuild filter with matching literal type */ } } Prevention
- Keep metadata field types consistent between ingestion and query time.
- Inspect stored metadata (e.g. one ListVectors result) before choosing filter literal types.
- Convert numeric strings once at ingestion rather than at filter time.
When it happens
Trigger: Filtering a field whose stored metadata type differs from the filter literal type — e.g. metadata stores age as "30" (String) but the filter uses new Filter.Value(30), or a Date-formatted string compared to a Date/Number — during S3VectorStore similaritySearch.
Common situations: Metadata written by earlier ingestion code with a different type (String vs number vs boolean); JSON round-trips that turned numbers into strings; comparing numbers to date strings; locale-specific comparable types.
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
- Unsupported operand type:
- Expression of type %s requires a right operand
- Expected a Key operand but got:
- Expected a Value operand but got:
- Cannot compare values of types %s and %s
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/5967b935e8026aac.
Report an issue: GitHub.