{"record":{"id":"ea9a2e8aadd9420c","repo":"spring-projects/spring-ai","slug":"unsupported-value-type-for-in-condition-only-supp","errorCode":null,"errorMessage":"Unsupported value type for IN condition. Only supports non-empty List of String or Number","messagePattern":"Unsupported value type for IN 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":189,"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.matchKeywords(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.matchValues(identifier, longValues);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new RuntimeException(\"Unsupported value in IN 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 IN condition. Only supports non-empty List of String or Number\");\n\n\t}\n\n\tprotected Condition buildNInCondition(Key key, Value value) {\n\t\tif (value.value() instanceof List valueList && !valueList.isEmpty()) {\n\t\t\tObject firstValue = valueList.get(0);\n\t\t\tString identifier = doKey(key);\n\n\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) {","sourceCodeStart":171,"sourceCodeEnd":207,"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#L171-L207","documentation":"buildInCondition requires the IN operand to be a non-empty List; passing any other value type (single scalar, null, map) or an empty List throws this RuntimeException. Qdrant's matchValues needs a collection of values to match against.","triggerScenarios":"Filter.builder().in(\"genre\", \"drama\").build() (scalar instead of list) or in(\"genre\", List.of()) (empty list) passed to the Qdrant vector store.","commonSituations":"Dynamic filter building where the values collection is optional and empty when no filters are selected — callers pass an empty list instead of omitting the expression entirely.","solutions":["Wrap scalar values in a List: in(\"genre\", List.of(\"drama\")).","Skip building the IN expression (or the whole filter) when the values collection is empty.","Coerce single values via Collections.singletonList before passing.","Guard call sites: if (values != null && !values.isEmpty()) { filter = Filter.builder().in(...) }."],"exampleFix":"// before\nFilter.builder().in(\"genre\", selectedGenres).build(); // selectedGenres may be empty\n// after\nif (selectedGenres != null && !selectedGenres.isEmpty()) {\n    filter = Filter.builder().in(\"genre\", selectedGenres).build();\n}","handlingStrategy":"validation","validationCode":"static boolean canBuildIn(Object operand) {\n    return operand instanceof List<?> l && !l.isEmpty();\n}\n// usage: only add the IN expression when canBuildIn(values) is true","typeGuard":"static boolean isNonEmptyList(Object v) {\n    return v instanceof List<?> l && !l.isEmpty();\n}","tryCatchPattern":"try {\n    vectorStore.similaritySearch(req);\n} catch (RuntimeException ex) {\n    if (ex.getMessage() != null && ex.getMessage().contains(\"Unsupported value type for IN condition\")) {\n        log.warn(\"IN filter skipped: operand was not a non-empty list\");\n        return vectorStore.similaritySearch(reqWithoutIn);\n    }\n    throw ex;\n}","preventionTips":["Wrap single values with List.of(value) before calling in().","Omit the IN expression entirely when the value collection is empty.","Guard dynamic filter builders with a non-empty-list check."],"tags":["qdrant","filter-expression","in","empty-list","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-23T08:17:48.524Z"}