{"record":{"id":"5967b935e8026aac","repo":"spring-projects/spring-ai","slug":"cannot-compare-values-of-incompatible-types-s-and-5967b9","errorCode":null,"errorMessage":"Cannot compare values of incompatible types %s and %s","messagePattern":"Cannot compare values of incompatible types (.+?) and (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"vector-stores/spring-ai-s3-vector-store/src/main/java/org/springframework/ai/vectorstore/s3/S3VectorStoreFilterExpressionEvaluator.java","lineNumber":142,"sourceCode":"\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\t@SuppressWarnings(\"unchecked\")\n\t\t\t\tint result = comparable.compareTo(filterVal);\n\t\t\t\treturn result;\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":124,"sourceCodeEnd":159,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/vector-stores/spring-ai-s3-vector-store/src/main/java/org/springframework/ai/vectorstore/s3/S3VectorStoreFilterExpressionEvaluator.java#L124-L159","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nnew Filter.Expression(Filter.ExpressionType.GT, new Filter.Key(\"age\"), new Filter.Value(30)) // metadata age is \"30\" String\n// after\nnew Filter.Expression(Filter.ExpressionType.GT, new Filter.Key(\"age\"), new Filter.Value(\"30\"))","handlingStrategy":"validation","validationCode":"static void assertSameScalarType(Object metadataSample, Object filterValue) {\n  if (metadataSample != null && !metadataSample.getClass().isInstance(filterValue)\n      && !(metadataSample instanceof Number && filterValue instanceof Number))\n    throw new IllegalStateException(\"Filter type \" + filterValue.getClass() + \" differs from metadata type \" + metadataSample.getClass());\n}","typeGuard":"static boolean comparableTypes(Object a, Object b) { return (a instanceof Number && b instanceof Number) || (a != null && b != null && a.getClass().equals(b.getClass())); }","tryCatchPattern":"try { store.similaritySearch(req); } catch (IllegalArgumentException e) { if (e.getMessage().startsWith(\"Cannot compare values of incompatible types\")) { /* rebuild filter with matching literal type */ } }","preventionTips":["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."],"tags":["vector-store","filter-expression","type-mismatch","post-filtering","aws-s3-vectors"],"backgroundTag":"type-mismatch","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}