{"record":{"id":"72018ee8280632f7","repo":"spring-projects/spring-ai","slug":"invalid-value-type-for-neq-can-either-be-a-string","errorCode":null,"errorMessage":"Invalid value type for NEQ. Can either be a string or Number","messagePattern":"Invalid value type for NEQ\\. Can either be a string or Number","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"vector-stores/spring-ai-qdrant-store/src/main/java/org/springframework/ai/vectorstore/qdrant/QdrantFilterExpressionConverter.java","lineNumber":119,"sourceCode":"\n\t\tthrow new IllegalArgumentException(\"Invalid value type for EQ. Can either be a string or Number\");\n\n\t}\n\n\tprotected Condition buildNeCondition(Key key, Value value) {\n\t\tString identifier = doKey(key);\n\t\tif (value.value() instanceof String valueStr) {\n\t\t\treturn io.qdrant.client.ConditionFactory.filter(Filter.newBuilder()\n\t\t\t\t.addMustNot(io.qdrant.client.ConditionFactory.matchKeyword(identifier, valueStr))\n\t\t\t\t.build());\n\t\t}\n\t\telse if (value.value() instanceof Number valueNum) {\n\t\t\tlong lValue = Long.parseLong(valueNum.toString());\n\t\t\tCondition condition = io.qdrant.client.ConditionFactory.match(identifier, lValue);\n\t\t\treturn io.qdrant.client.ConditionFactory.filter(Filter.newBuilder().addMustNot(condition).build());\n\t\t}\n\n\t\tthrow new IllegalArgumentException(\"Invalid value type for NEQ. Can either be a string or Number\");\n\n\t}\n\n\tprotected Condition buildGtCondition(Key key, Value value) {\n\t\tString identifier = doKey(key);\n\t\tif (value.value() instanceof Number valueNum) {\n\t\t\tDouble dvalue = Double.parseDouble(valueNum.toString());\n\t\t\treturn io.qdrant.client.ConditionFactory.range(identifier, Range.newBuilder().setGt(dvalue).build());\n\t\t}\n\t\tthrow new RuntimeException(\"Unsupported value type for GT condition. Only supports Number\");\n\n\t}\n\n\tprotected Condition buildLtCondition(Key key, Value value) {\n\t\tString identifier = doKey(key);\n\t\tif (value.value() instanceof Number valueNum) {\n\t\t\tDouble dvalue = Double.parseDouble(valueNum.toString());\n\t\t\treturn io.qdrant.client.ConditionFactory.range(identifier, Range.newBuilder().setLt(dvalue).build());","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/vector-stores/spring-ai-qdrant-store/src/main/java/org/springframework/ai/vectorstore/qdrant/QdrantFilterExpressionConverter.java#L101-L137","documentation":"Filter translation guard in QdrantFilterExpressionConverter.buildNeCondition: a FilterExpression NEQ comparison was given a right-hand value that is neither a String nor a Number, which Qdrant match conditions cannot represent.","triggerScenarios":"filterExpression(NE) whose right Value is a Boolean, null, date, or List — e.g. Filter.builder().ne(\"status\", true).build() sent to the Qdrant store.","commonSituations":"Same as EQ: boolean or date metadata fields being negated in a filter; typical when metadata was ingested with heterogeneous JSON types.","solutions":["Use a String or Number value in the NEQ expression","Convert boolean/other types to a supported representation before filtering"],"exampleFix":"// before\nFilter.builder().ne(\"deleted\", true).build();\n// after\nFilter.builder().ne(\"deleted\", \"true\").build();","handlingStrategy":"validation","validationCode":"static void checkNeOperand(Object v) {\n    if (!(v instanceof String) && !(v instanceof Number)) {\n        throw new IllegalArgumentException(\"NE operand must be String or Number, got \" + (v == null ? \"null\" : v.getClass()));\n    }\n}","typeGuard":"static boolean isNeCompatible(Object v) {\n    return v instanceof String || v instanceof Number;\n}","tryCatchPattern":"try {\n    vectorStore.similaritySearch(req);\n} catch (IllegalArgumentException ex) {\n    if (ex.getMessage() != null && ex.getMessage().startsWith(\"Invalid value type for NEQ\")) {\n        throw new IllegalArgumentException(\"NE operand must be String or Number\", ex);\n    }\n    throw ex;\n}","preventionTips":["Encode booleans as \"true\"/\"false\" strings or 0/1 numbers in metadata.","Convert dates to epoch numbers before ne().","Assert operand types in your filter-builder utility."],"tags":["qdrant","filter-expression","neq","type-mismatch","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-14T11:17:12.474Z"}