{"record":{"id":"d9fbeff6a98cad6a","repo":"spring-projects/spring-ai","slug":"cannot-compare-values-of-types-s-and-s-d9fbef","errorCode":null,"errorMessage":"Cannot compare values of types %s and %s","messagePattern":"Cannot compare values of 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":146,"sourceCode":"\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":128,"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#L128-L159","documentation":"compare() throws this when neither null/Number/equals handling applies and at least one side is not Comparable — for example comparing metadata against a Boolean or a Map/List where equality also failed. Unlike error 628 this is not a ClassCastException but a static inability to order the two values.","triggerScenarios":"Using an ordering operator (GT/GTE/LT/LTE) or IN/NIN whose element comparison lands here: e.g. metadata field holds a Boolean/List while the filter literal is a String/Number, or metadata contains a nested object that is not Comparable, during S3VectorStore similaritySearch.","commonSituations":"Ordering filters on boolean fields (booleans are not Comparable against other types here); metadata ingested as JSON arrays/objects then used in range filters; type drift between ingestion and query time.","solutions":["Use EQ/NE (or IN/NIN) for non-Comparable values like Booleans, Lists, or objects instead of GT/LT range operators.","Ensure the metadata field holds a scalar Comparable type (String or Number) consistent with the filter literal type.","Fix ingestion so structured values (lists/maps) are not stored in fields used for range filtering.","Pre-filter such documents client-side after retrieval instead of relying on the evaluator's comparison."],"exampleFix":"// before\nnew Filter.Expression(Filter.ExpressionType.GT, new Filter.Key(\"enabled\"), new Filter.Value(false))\n// after\nnew Filter.Expression(Filter.ExpressionType.EQ, new Filter.Key(\"enabled\"), new Filter.Value(true))","handlingStrategy":"validation","validationCode":"static void assertOrderable(Filter.ExpressionType t, Object filterValue) {\n  if (List.of(GT, GTE, LT, LTE).contains(t) && !(filterValue instanceof Number || filterValue instanceof String || filterValue instanceof Date))\n    throw new IllegalStateException(\"Range operators need Number/String/Date, got \" + filterValue.getClass());\n}","typeGuard":"static boolean orderable(Object v) { return v instanceof Number || v instanceof String || v instanceof Comparable; }","tryCatchPattern":"try { store.similaritySearch(req); } catch (IllegalArgumentException e) { if (e.getMessage().startsWith(\"Cannot compare values of types\")) { /* switch to EQ/NE or fix metadata scalar type */ } }","preventionTips":["Reserve GT/GTE/LT/LTE for Number and String (or date-string) metadata.","Use EQ/NE/IN/NIN for Booleans, Lists, and structured metadata.","Avoid storing JSON objects/arrays in fields you plan to range-filter."],"tags":["vector-store","filter-expression","type-mismatch","comparison","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"}