{"record":{"id":"088008e088793b1f","repo":"spring-projects/spring-ai","slug":"expression-type-s-not-yet-implemented-patches-we","errorCode":null,"errorMessage":"Expression type %s not yet implemented. Patches welcome.","messagePattern":"Expression type (.+?) not yet implemented\\. Patches welcome\\.","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/vectorstore/cassandra/CassandraFilterExpressionConverter.java","lineNumber":69,"sourceCode":"\n\t\tthis.columnsByName = columns.stream()\n\t\t\t.collect(Collectors.toMap(c -> c.getName().asInternal(), Function.identity()));\n\t}\n\n\tprivate static void doOperand(ExpressionType type, StringBuilder context) {\n\t\tswitch (type) {\n\t\t\tcase EQ -> context.append(\" = \");\n\t\t\tcase NE -> context.append(\" != \");\n\t\t\tcase GT -> context.append(\" > \");\n\t\t\tcase GTE -> context.append(\" >= \");\n\t\t\tcase IN -> context.append(\" IN \");\n\t\t\tcase LT -> context.append(\" < \");\n\t\t\tcase LTE -> context.append(\" <= \");\n\t\t\t// TODO SAI supports collections\n\t\t\t// reach out to mck@apache.org if you'd like these implemented\n\t\t\t// case CONTAINS -> context.append(\" CONTAINS \");\n\t\t\t// case CONTAINS_KEY -> context.append(\" CONTAINS_KEY \");\n\t\t\tdefault -> throw new UnsupportedOperationException(\n\t\t\t\t\tString.format(\"Expression type %s not yet implemented. Patches welcome.\", type));\n\t\t}\n\t}\n\n\t@Override\n\tprotected void doKey(Key key, StringBuilder context) {\n\t\tString keyName = key.key();\n\t\tOptional<ColumnMetadata> column = getColumn(keyName);\n\t\tPreconditions.checkArgument(column.isPresent(), \"No metafield %s has been configured\", keyName);\n\t\tcontext.append(column.get().getName().asCql(false));\n\t}\n\n\t@Override\n\tprotected void doExpression(Filter.Expression expression, StringBuilder context) {\n\t\tswitch (expression.type()) {\n\t\t\tcase AND -> doBinaryOperation(\" and \", expression, context);\n\t\t\tcase OR -> doBinaryOperation(\" or \", expression, context);\n\t\t\tcase NIN, NOT -> throw new UnsupportedOperationException(","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/vectorstore/cassandra/CassandraFilterExpressionConverter.java#L51-L87","documentation":"The Cassandra filter expression converter translates Spring AI Filter.Expression types into CQL. doOperand throws this UnsupportedOperationException when it encounters an expression type it cannot render as a CQL operator (e.g. CONTAINS/CONTAINS_KEY, which are commented out pending collection support). It signals an unsupported filter feature, not a runtime fault.","triggerScenarios":"Building a Filter.ExpressionBuilder filter containing an expression type other than EQ, NE, GT, GTE, LT, LTE, IN, AND, OR — specifically CONTAINS or CONTAINS_KEY on a metadata field — and passing it to CassandraVectorStore similaritySearch or delete with a FilterExpressionTextParser-generated expression.","commonSituations":"Developers port filters written for PgVector or other stores that support CONTAINS on arrays; using filter expressions with collection/JSON metadata fields against Cassandra where SAI collection operators are not yet wired up.","solutions":["Remove CONTAINS/CONTAINS_KEY predicates from your filter; restructure metadata so equality/range/IN comparisons suffice (e.g. store collection membership as separate boolean fields).","Filter collections client-side: issue the Cassandra query without the unsupported predicate and post-filter the returned Documents in Java.","Contribute the missing operator: implement the commented-out CONTAINS branches in CassandraFilterExpressionConverter.doOperand using Cassandra SAI CONTAINS syntax."],"exampleFix":"// before\nFilter.expr(\"metadata.tags\").contains(\"ai\")\n// after (client-side filtering)\nvar docs = vectorStore.similaritySearch(SearchRequest.query(q).withFilterExpression(Filter.expr(\"metadata.topic\").eq(\"ai\")));\ndocs = docs.stream().filter(d -> d.getMetadata().get(\"tags\", List.of()).contains(\"ai\")).toList();","handlingStrategy":"validation","validationCode":"Set<Filter.ExpressionType> SUPPORTED = Set.of(EQ, NE, GT, GTE, LT, LTE, IN, AND, OR);\nvoid validate(Filter.Expression e) {\n  if (!SUPPORTED.contains(e.type())) throw new IllegalArgumentException(\"Unsupported for Cassandra: \" + e.type());\n  if (e.left() instanceof Filter.Expression l) validate(l);\n  if (e.right() instanceof Filter.Expression r) validate(r);\n}","typeGuard":"boolean isCassandraSupported(Filter.Expression e) {\n  return e.type() == EQ || e.type() == NE || e.type() == GT || e.type() == GTE\n      || e.type() == LT || e.type() == LTE || e.type() == IN || e.type() == AND || e.type() == OR;\n}","tryCatchPattern":"try {\n  vectorStore.similaritySearch(request);\n} catch (UnsupportedOperationException e) {\n  // fall back to an unfiltered search plus client-side filtering\n}","preventionTips":["Restrict filter DSLs for Cassandra to comparison, IN and boolean operators.","Never use CONTAINS/CONTAINS_KEY filters with the Cassandra store.","Unit-test every dynamically built filter against a support matrix before shipping."],"tags":["cassandra","filter-expression","unsupported-operation","vector-store"],"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"}