{"record":{"id":"aebe158b05799a7f","repo":"spring-projects/spring-ai","slug":"unsupported-expression-type","errorCode":null,"errorMessage":"Unsupported expression type: ","messagePattern":"Unsupported expression type: ","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":88,"sourceCode":"\n\t\t}\n\n\t\treturn context.addAllMust(mustClauses).addAllShould(shouldClauses).addAllMustNot(mustNotClauses).build();\n\t}\n\n\tprotected Condition parseComparison(Key key, Value value, Expression exp) {\n\n\t\tExpressionType type = exp.type();\n\t\treturn switch (type) {\n\t\t\tcase EQ -> buildEqCondition(key, value);\n\t\t\tcase NE -> buildNeCondition(key, value);\n\t\t\tcase GT -> buildGtCondition(key, value);\n\t\t\tcase GTE -> buildGteCondition(key, value);\n\t\t\tcase LT -> buildLtCondition(key, value);\n\t\t\tcase LTE -> buildLteCondition(key, value);\n\t\t\tcase IN -> buildInCondition(key, value);\n\t\t\tcase NIN -> buildNInCondition(key, value);\n\t\t\tdefault -> throw new RuntimeException(\"Unsupported expression type: \" + type);\n\t\t};\n\t}\n\n\tprotected Condition buildEqCondition(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.matchKeyword(identifier, valueStr);\n\t\t}\n\t\telse if (value.value() instanceof Number valueNum) {\n\t\t\tlong lValue = Long.parseLong(valueNum.toString());\n\t\t\treturn io.qdrant.client.ConditionFactory.match(identifier, lValue);\n\t\t}\n\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) {","sourceCodeStart":70,"sourceCodeEnd":106,"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#L70-L106","documentation":"parseComparison switches on the Filter.Expression's ExpressionType and maps EQ, NE, GT, GTE, LT, LTE, IN and NIN to Qdrant conditions. Any other type reaching a comparison (because the message says \"Unsupported expression type: \" without even appending the type) throws a RuntimeException. It indicates an expression type that Qdrant translation does not implement.","triggerScenarios":"Passing a filterExpression containing an unsupported ExpressionType to the Qdrant vector store — typically types that should have been handled by group logic (AND/OR/NOT) but reached parseComparison due to a converter bug, or exotic types from a custom ExpressionType enum.","commonSituations":"Rare in practice; usually seen when a shared filter-conversion utility passes group expressions straight into comparison parsing, or when new Spring AI ExpressionType values are added that the Qdrant converter has not been updated for.","solutions":["Restrict filter expressions to the supported set: EQ, NE, GT, GTE, LT, LTE, IN, NIN plus group operators AND/OR/NOT.","Check the Qdrant converter version and upgrade spring-ai-qdrant-store so newer expression types are supported.","Pre-process/reduce the expression (e.g. split unsupported combinators into multiple queries) before passing it to Qdrant.","If you subclass QdrantFilterExpressionConverter, override parseComparison to handle your custom types."],"exampleFix":"// before\nFilter.builder().not(Filter.builder().eq(\"genre\",\"drama\").build()) // unsupported combinator in some paths\n// after\nFilter.builder().nin(\"genre\", List.of(\"drama\")).build();","handlingStrategy":"validation","validationCode":"static final Set<ExpressionType> SUPPORTED = Set.of(EQ, NE, GT, GTE, LT, LTE, IN, NIN, AND, OR, NOT);\nstatic void assertSupported(Filter.Expression e) {\n    if (!SUPPORTED.contains(e.type())) throw new IllegalArgumentException(\"Unsupported type \" + e.type());\n}","typeGuard":"static boolean qdrantSupports(ExpressionType t) {\n    return t == ExpressionType.EQ || t == ExpressionType.NE || t == ExpressionType.GT || t == ExpressionType.GTE\n        || t == ExpressionType.LT || t == ExpressionType.LTE || t == ExpressionType.IN || t == ExpressionType.NIN;\n}","tryCatchPattern":"try {\n    return vectorStore.similaritySearch(req);\n} catch (RuntimeException ex) {\n    if (ex.getMessage() != null && ex.getMessage().startsWith(\"Unsupported expression type\")) {\n        log.warn(\"Filter dropped, unsupported expression\", ex);\n        return vectorStore.similaritySearch(reqWithoutFilter);\n    }\n    throw ex;\n}","preventionTips":["Stick to the documented expression types for Qdrant.","Upgrade spring-ai-qdrant-store when new ExpressionTypes appear upstream.","Centralize filter construction in one utility so unsupported types are caught early."],"tags":["qdrant","filter-expression","unsupported-operator","spring-ai"],"backgroundTag":"unsupported-operation","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"}