{"record":{"id":"0acc6d12fbe94238","repo":"spring-projects/spring-ai","slug":"cannot-compare-values-of-incompatible-types-s-and","errorCode":null,"errorMessage":"Cannot compare values of incompatible types %s and %s","messagePattern":"Cannot compare values of incompatible types (.+?) and (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStoreFilterExpressionEvaluator.java","lineNumber":205,"sourceCode":"\t\t}\n\t\tif (metaVal == null) {\n\t\t\treturn -1;\n\t\t}\n\t\tif (filterVal == null) {\n\t\t\treturn 1;\n\t\t}\n\t\tif (metaVal instanceof Number n1 && filterVal instanceof Number n2) {\n\t\t\treturn Double.compare(n1.doubleValue(), n2.doubleValue());\n\t\t}\n\t\tif (Objects.equals(metaVal, filterVal)) {\n\t\t\treturn 0;\n\t\t}\n\t\tif (metaVal instanceof Comparable comparable && filterVal instanceof Comparable) {\n\t\t\ttry {\n\t\t\t\treturn comparable.compareTo(filterVal);\n\t\t\t}\n\t\t\tcatch (ClassCastException ex) {\n\t\t\t\tthrow new IllegalArgumentException(\"Cannot compare values of incompatible types %s and %s\"\n\t\t\t\t\t.formatted(metaVal.getClass().getName(), filterVal.getClass().getName()), ex);\n\t\t\t}\n\t\t}\n\t\tthrow new IllegalArgumentException(\"Cannot compare values of types %s and %s\"\n\t\t\t.formatted(metaVal.getClass().getName(), filterVal.getClass().getName()));\n\t}\n\n\tprivate List<?> asList(Object value, Filter.Expression expression) {\n\t\tif (value instanceof List<?> list) {\n\t\t\treturn list;\n\t\t}\n\t\tthrow new IllegalArgumentException(\n\t\t\t\t\"Expected a List value for %s expression but got: %s\".formatted(expression.type(), value));\n\t}\n\n}\n","sourceCodeStart":187,"sourceCodeEnd":222,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStoreFilterExpressionEvaluator.java#L187-L222","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n// metadata: {\"year\": \"2020\"} filtered with\nnew Filter.Expression(GT, new Filter.Key(\"year\"), new Filter.Value(2019));\n// after\nnew Filter.Expression(GT, new Filter.Key(\"year\"), new Filter.Value(\"2019\")); // or store year as Integer","handlingStrategy":"validation","validationCode":"boolean typesMatch(Document doc, String key, Object literal) {\n    Object meta = doc.getMetadata().get(key);\n    return meta != null && literal != null\n        && (meta.getClass().equals(literal.getClass())\n            || (meta instanceof Number && literal instanceof Number));\n}","typeGuard":null,"tryCatchPattern":"try {\n    vectorStore.similaritySearch(request);\n} catch (IllegalArgumentException ex) {\n    if (ex.getMessage().startsWith(\"Cannot compare values of incompatible types\")) {\n        // fix literal type or normalize metadata and retry\n    } else throw ex;\n}","preventionTips":["Enforce consistent metadata types at ingestion time","Quote string literals in text filters to avoid numeric coercion mismatches"],"tags":["vector-store","filter-expression","type-mismatch","comparison","spring-ai"],"backgroundTag":"type-mismatch","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}