{"record":{"id":"8182f0845c7c3161","repo":"spring-projects/spring-ai","slug":"unsupported-value-in-nin-value-list-only-supports","errorCode":null,"errorMessage":"Unsupported value in NIN value list. Only supports String or Number","messagePattern":"Unsupported value in NIN value list\\. Only supports String or Number","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"vector-stores/spring-ai-qdrant-store/src/main/java/org/springframework/ai/vectorstore/qdrant/QdrantFilterExpressionConverter.java","lineNumber":217,"sourceCode":"\t\t\tif (firstValue instanceof String) {\n\t\t\t\t// If the first value is a string, then all values should be strings\n\t\t\t\tList<String> stringValues = new ArrayList<>();\n\t\t\t\tfor (Object valueObj : valueList) {\n\t\t\t\t\tstringValues.add(valueObj.toString());\n\t\t\t\t}\n\t\t\t\treturn io.qdrant.client.ConditionFactory.matchExceptKeywords(identifier, stringValues);\n\t\t\t}\n\t\t\telse if (firstValue instanceof Number) {\n\t\t\t\t// If the first value is a number, then all values should be numbers\n\t\t\t\tList<Long> longValues = new ArrayList<>();\n\t\t\t\tfor (Object valueObj : valueList) {\n\t\t\t\t\tLong longValue = Long.parseLong(valueObj.toString());\n\t\t\t\t\tlongValues.add(longValue);\n\t\t\t\t}\n\t\t\t\treturn io.qdrant.client.ConditionFactory.matchExceptValues(identifier, longValues);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new RuntimeException(\"Unsupported value in NIN value list. Only supports String or Number\");\n\t\t\t}\n\t\t}\n\t\tthrow new RuntimeException(\n\t\t\t\t\"Unsupported value type for NIN condition. Only supports non-empty List of String or Number\");\n\n\t}\n\n\tprotected String doKey(Key key) {\n\t\tvar identifier = (hasOuterQuotes(key.key())) ? removeOuterQuotes(key.key()) : key.key();\n\t\treturn identifier;\n\t}\n\n\tprotected boolean hasOuterQuotes(String str) {\n\t\tstr = str.trim();\n\t\treturn (str.startsWith(\"\\\"\") && str.endsWith(\"\\\"\")) || (str.startsWith(\"'\") && str.endsWith(\"'\"));\n\t}\n\n\tprotected String removeOuterQuotes(String in) {","sourceCodeStart":199,"sourceCodeEnd":235,"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#L199-L235","documentation":"QdrantFilterExpressionConverter.buildNInCondition converts a Filter.Expression NIN operation into a Qdrant match-except condition. Every element of the list must be a String or a Number (Integer/Long/Double/Float); anything else, or an empty/invalid list, makes the condition unrepresentable so the converter throws this RuntimeException. It is thrown from inside expression conversion, so it surfaces when a filter is being translated for a search or delete call.","triggerScenarios":"Passing a NIN FilterExpression whose value list contains a Boolean, a nested List, a Map, or null; e.g. new Filter.Expression(NIN, meta(\"color\"), new Value(List.of(\"red\", true))).","commonSituations":"Building filter expressions programmatically from untyped metadata where a value of an unexpected type (boolean, nested array) slips into the NIN list; passing an empty list; passing a raw non-list value.","solutions":["Ensure every element in the NIN value list is a String or a numeric type (Integer/Long/Double/Float)","Convert unsupported element types before building the expression (e.g. boolean -> string)","Use NIN only with a non-empty java.util.List value","If you need mixed/complex matching, split into multiple expressions or pre-filter client-side"],"exampleFix":"// before\nFilter.expr(\"color\").nin(List.of(\"red\", true));\n// after\nFilter.expr(\"color\").nin(List.of(\"red\", \"blue\")); // Strings or Numbers only","handlingStrategy":"validation","validationCode":"if (!(v instanceof List<?> list) || list.isEmpty() || list.stream().anyMatch(e -> !(e instanceof String) && !(e instanceof Number))) throw new IllegalArgumentException(\"NIN requires non-empty List of String/Number\");","typeGuard":"static boolean isNinSafe(Object v) { return v instanceof List<?> l && !l.isEmpty() && l.stream().allMatch(e -> e instanceof String || e instanceof Number); }","tryCatchPattern":"try { store.similaritySearch(req); } catch (RuntimeException e) { if (e.getMessage().contains(\"NIN\")) { /* fix filter */ } else throw e; }","preventionTips":["Only pass List.of(...) of Strings or Numbers to nin()","Validate element types when building filters from dynamic metadata","Never put booleans, maps, or nested lists in NIN operands"],"tags":["qdrant","filter-expression","vector-store","spring-ai"],"backgroundTag":"invalid-argument-value","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"}