{"record":{"id":"61e41fe441c48e50","repo":"spring-projects/spring-ai","slug":"unexpected-value-expressiontype","errorCode":null,"errorMessage":"Unexpected value: {expressionType}","messagePattern":"Unexpected value: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"vector-stores/spring-ai-coherence-store/src/main/java/org/springframework/ai/vectorstore/coherence/CoherenceFilterExpressionConverter.java","lineNumber":72,"sourceCode":"\n\tprivate Filter<?> convert(Expression expression) {\n\t\tif (expression.type() == ExpressionType.NOT) {\n\t\t\treturn convert(FilterHelper.negate(expression));\n\t\t}\n\t\tAssert.state(expression.right() != null, \"expression is expected to have a right operand\");\n\t\treturn switch (expression.type()) {\n\t\t\tcase EQ -> Filters.equal(extractor(expression.left()), value(expression.right()));\n\t\t\tcase NE -> Filters.notEqual(extractor(expression.left()), value(expression.right()));\n\t\t\tcase GT -> Filters.greater(extractor(expression.left()), value(expression.right()));\n\t\t\tcase GTE -> Filters.greaterEqual(extractor(expression.left()), value(expression.right()));\n\t\t\tcase LT -> Filters.less(extractor(expression.left()), value(expression.right()));\n\t\t\tcase LTE -> Filters.lessEqual(extractor(expression.left()), value(expression.right()));\n\t\t\tcase IN -> Filters.in(extractor(expression.left()), ((List) value(expression.right())).toArray());\n\t\t\tcase NIN ->\n\t\t\t\tFilters.not(Filters.in(extractor(expression.left()), ((List) value(expression.right())).toArray()));\n\t\t\tcase AND -> Filters.all(convert(expression.left()), convert(expression.right()));\n\t\t\tcase OR -> Filters.any(convert(expression.left()), convert(expression.right()));\n\t\t\tdefault -> throw new IllegalStateException(\"Unexpected value: \" + expression.type());\n\t\t};\n\t}\n\n\tprivate ValueExtractor extractor(Operand op) {\n\t\treturn new ChainedExtractor(new UniversalExtractor<>(\"metadata\"), new UniversalExtractor<>(((Key) op).key()));\n\t}\n\n\tprivate <T> T value(Operand op) {\n\t\treturn (T) ((Value) op).value();\n\t}\n\n}\n","sourceCodeStart":54,"sourceCodeEnd":85,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/vector-stores/spring-ai-coherence-store/src/main/java/org/springframework/ai/vectorstore/coherence/CoherenceFilterExpressionConverter.java#L54-L85","documentation":"CoherenceFilterExpressionConverter.convert maps Spring AI Filter.Expression types to Coherence Filters and ends with a default branch that throws IllegalStateException for any unsupported type. It is an exhaustiveness guard: the switch only supports EQ, NE, GT, GTE, LT, LTE, IN, NIN, AND, OR.","triggerScenarios":"Passing a filter containing NOT or CONTAINS/CONTAINS_KEY (or any type outside the switch) to a Coherence-backed vector store similaritySearch or delete.","commonSituations":"Using Filter.not(...) built from FilterExpressionTextParser output; porting filters from stores that support contains on arrays; expanding a dynamic filter DSL with new operators not yet mapped.","solutions":["Rewrite NOT via De Morgan's laws using AND/OR/NE (e.g. not(a.eq(x)) -> a.ne(x)).","Replace CONTAINS with EQ on scalar fields or IN over known values; move array-membership filtering to application code.","Extend the converter's switch to map the missing type to Coherence Filters (e.g. Filters.not(...))."],"exampleFix":"// before\nFilter.expr(\"metadata.role\").not(\"admin\")\n// after\nFilter.expr(\"metadata.role\").ne(\"admin\")","handlingStrategy":"validation","validationCode":"Set<Filter.ExpressionType> OK = Set.of(EQ, NE, GT, GTE, LT, LTE, IN, NIN, AND, OR);\nvoid check(Filter.Expression e) {\n  if (!OK.contains(e.type())) throw new IllegalArgumentException(\"Unsupported for Coherence: \" + e.type());\n  if (e.left() instanceof Filter.Expression l) check(l);\n  if (e.right() instanceof Filter.Expression r) check(r);\n}","typeGuard":"boolean coherenceSafe(Filter.Expression e) {\n  return !(e.type() == NOT || e.type() == CONTAINS || e.type() == CONTAINS_KEY);\n}","tryCatchPattern":"try {\n  vectorStore.similaritySearch(request);\n} catch (IllegalStateException e) {\n  if (e.getMessage().startsWith(\"Unexpected value\")) {\n    // fall back to unfiltered search + client-side filtering\n  }\n}","preventionTips":["Avoid Filter.not(...) with the Coherence store; rewrite as NE/De Morgan.","Keep an explicit allow-list of operators per vector store in shared filter-building code.","Cover all operators in integration tests when adding new filter producers."],"tags":["coherence","filter-expression","unsupported-operation","vector-store","state-exception"],"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"}