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

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.

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)

Solutions

  1. Make filter literal types match the stored metadata types (compare '2020' == '2020' or 2020 == 2020).
  2. Normalize metadata types at ingestion time (store numbers as numbers, dates as ISO strings).
  3. 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

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


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