{"record":{"id":"8737bc5f2931254b","repo":"spring-projects/spring-ai","slug":"expression-type-0-not-supported-for-numeric-fiel","errorCode":null,"errorMessage":"Expression type {0} not supported for numeric fields","messagePattern":"Expression type (.+?) not supported for numeric fields","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"vector-stores/spring-ai-redis-store/src/main/java/org/springframework/ai/vectorstore/redis/RedisFilterExpressionConverter.java","lineNumber":197,"sourceCode":"\t}\n\n\tprivate String tagValueDelimiter(Expression expression) {\n\t\treturn switch (expression.type()) {\n\t\t\tcase IN -> \" | \";\n\t\t\tcase EQ -> \" \";\n\t\t\tdefault -> throw new UnsupportedOperationException(\n\t\t\t\t\tMessageFormat.format(\"Tag operand {0} not supported\", expression.type()));\n\t\t};\n\t}\n\n\tprivate Numeric numeric(Expression expression, Value value) {\n\t\treturn switch (expression.type()) {\n\t\t\tcase EQ -> new Numeric(inclusive(value), inclusive(value));\n\t\t\tcase GT -> new Numeric(exclusive(value), NumericBoundary.POSITIVE_INFINITY);\n\t\t\tcase GTE -> new Numeric(inclusive(value), NumericBoundary.POSITIVE_INFINITY);\n\t\t\tcase LT -> new Numeric(NumericBoundary.NEGATIVE_INFINITY, exclusive(value));\n\t\t\tcase LTE -> new Numeric(NumericBoundary.NEGATIVE_INFINITY, inclusive(value));\n\t\t\tdefault -> throw new UnsupportedOperationException(\n\t\t\t\t\tMessageFormat.format(\"Expression type {0} not supported for numeric fields\", expression.type()));\n\t\t};\n\t}\n\n\tprivate NumericBoundary inclusive(Value value) {\n\t\tif (!(value.value() instanceof Number)) {\n\t\t\tthrow new IllegalArgumentException(\"Numeric value must be a Number\");\n\t\t}\n\t\treturn new NumericBoundary(value.value(), false);\n\t}\n\n\tprivate NumericBoundary exclusive(Value value) {\n\t\tif (!(value.value() instanceof Number)) {\n\t\t\tthrow new IllegalArgumentException(\"Numeric value must be a Number\");\n\t\t}\n\t\treturn new NumericBoundary(value.value(), true);\n\t}\n","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/vector-stores/spring-ai-redis-store/src/main/java/org/springframework/ai/vectorstore/redis/RedisFilterExpressionConverter.java#L179-L215","documentation":"RedisFilterExpressionConverter.numeric() only supports the comparison operators EQ, GT, GTE, LT and LTE when translating a Filter.Expression into a Redis numeric range. Any other expression type (e.g. NIN, AND, OR, IN applied to a numeric field) hits the default branch and throws this UnsupportedOperationException. It signals that the filter expression uses an operator the Redis numeric-range mapping cannot express.","triggerScenarios":"Calling RedisVectorStore.similaritySearch() with a FilterExpressionBuilder expression whose type is not one of EQ/GT/GTE/LT/LTE on a numeric metadata field, e.g. a NIN or NE expression, or a top-level boolean expression passed where numeric() is invoked.","commonSituations":"Building filters with FilterExpressionBuilder.ne() or .nin() on a numeric field like 'year' or 'price'; porting filters written for another vector store that supports more operators; framework upgrades where new expression types appear but the converter was not extended.","solutions":["Use only supported operators (EQ, GT, GTE, LT, LTE) for numeric fields in your filter expression","Express the negation differently, e.g. combine GT and LT ranges instead of NE/NIN","If you control the code, extend RedisFilterExpressionConverter to map the missing expression type to an equivalent Redis range or tag set"],"exampleFix":"// before\nFilter.Expression expr = new FilterExpressionBuilder().nin(\"year\", 2020, 2021).build();\n// after\nFilter.Expression expr = new FilterExpressionBuilder().and(\n    new FilterExpressionBuilder().lt(\"year\", 2020).build(),\n    new FilterExpressionBuilder().gt(\"year\", 2021).build());","handlingStrategy":"validation","validationCode":"java.util.Set<Filter.ExpressionType> SUPPORTED = Set.of(Filter.ExpressionType.EQ, Filter.ExpressionType.GT, Filter.ExpressionType.GTE, Filter.ExpressionType.LT, Filter.ExpressionType.LTE);\nif (!SUPPORTED.contains(expr.type())) throw new IllegalArgumentException(\"Unsupported numeric operator: \" + expr.type());","typeGuard":null,"tryCatchPattern":"try { store.similaritySearch(req); } catch (UnsupportedOperationException e) { log.warn(\"Filter operator not supported for numeric fields\", e); }","preventionTips":["Restrict numeric filters to EQ/GT/GTE/LT/LTE","Replace NE/NIN with combined range or negated-tag expressions","Unit-test filter expressions against the Redis converter"],"tags":["redis","vector-store","filter-expression","unsupported-operation"],"backgroundTag":"unsupported-operation","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"}