{"record":{"id":"c6c9d96ea18019e4","repo":"spring-projects/spring-ai","slug":"unsupported-value-type-for-nin-condition-only-sup","errorCode":null,"errorMessage":"Unsupported value type for NIN condition. Only supports non-empty List of String or Number","messagePattern":"Unsupported value type for NIN condition\\. Only supports non-empty List of 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":220,"sourceCode":"\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) {\n\t\treturn in.substring(1, in.length() - 1);\n\t}\n","sourceCodeStart":202,"sourceCodeEnd":238,"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#L202-L238","documentation":"buildNInCondition requires the NIN operation's value to be a non-empty java.util.List whose elements are Strings or Numbers. If the operand is not a List at all (single value, null, or other collection type), the converter cannot build a Qdrant match-except condition and throws this RuntimeException after the per-element checks.","triggerScenarios":"Calling nin() with a single value instead of a list, e.g. Filter.expr(\"tag\").nin(\"red\"), or passing null/empty collection, or a value object that is not a List.","commonSituations":"Confusing EQ/NIN semantics and passing a scalar to NIN; building expressions dynamically where the value may be null; migrating from another store whose NIN accepted scalars.","solutions":["Wrap the operand in java.util.List before using NIN: Filter.expr(\"tag\").nin(List.of(\"red\"))","Use EQ/NE instead of NIN when matching a single value","Ensure the list is non-empty and elements are String or Number","Validate the expression value type before passing it to the vector store"],"exampleFix":"// before\nnew Filter.Expression(ExpressionType.NIN, meta(\"tag\"), new Value(\"red\"));\n// after\nnew Filter.Expression(ExpressionType.NIN, meta(\"tag\"), new Value(List.of(\"red\")));","handlingStrategy":"validation","validationCode":"if (!(value instanceof List<?> list) || list.isEmpty()) throw new IllegalArgumentException(\"NIN operand must be a non-empty List\");","typeGuard":"static boolean isNinList(Object v) { return v instanceof List<?> l && !l.isEmpty(); }","tryCatchPattern":"try { store.delete(expr); } catch (RuntimeException e) { if (e.getMessage().startsWith(\"Unsupported value type for NIN\")) { /* wrap scalar in List */ } else throw e; }","preventionTips":["Always pass a java.util.List to nin()","Use eq()/ne() for single values","Null-check dynamically built operand values before wrapping in Value"],"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"}