{"record":{"id":"0895460339ad8a0e","repo":"spring-projects/spring-ai","slug":"not-supported-expression-type-089546","errorCode":null,"errorMessage":"Not supported expression type:","messagePattern":"Not supported expression type:","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"vector-stores/spring-ai-typesense-store/src/main/java/org/springframework/ai/vectorstore/typesense/TypesenseFilterExpressionConverter.java","lineNumber":52,"sourceCode":"\t\tthis.convertOperand(exp.left(), context);\n\t\tcontext.append(getOperationSymbol(exp));\n\t\tthis.convertOperand(exp.right(), context);\n\t}\n\n\tprivate String getOperationSymbol(Filter.Expression exp) {\n\t\treturn switch (exp.type()) {\n\t\t\tcase AND -> \" && \";\n\t\t\tcase OR -> \" || \";\n\t\t\tcase EQ -> \" \"; // in typesense \"EQ\" operator looks like -> country:USA\n\t\t\tcase NE -> \" != \";\n\t\t\tcase LT -> \" < \";\n\t\t\tcase LTE -> \" <= \";\n\t\t\tcase GT -> \" > \";\n\t\t\tcase GTE -> \" >= \";\n\t\t\tcase IN -> \" \"; // in typesense \"IN\" operator looks like -> country: [USA, UK]\n\t\t\tcase NIN -> \" != \"; // in typesense \"NIN\" operator looks like -> country:\n\t\t\t// !=[USA, UK]\n\t\t\tdefault -> throw new RuntimeException(\"Not supported expression type:\" + exp.type());\n\t\t};\n\t}\n\n\t@Override\n\tprotected void doGroup(Filter.Group group, StringBuilder context) {\n\t\tthis.convertOperand(new Filter.Expression(Filter.ExpressionType.AND, group.content(), group.content()),\n\t\t\t\tcontext); // trick\n\t}\n\n\t@Override\n\tprotected void doKey(Filter.Key key, StringBuilder context) {\n\t\tvar identifier = (hasOuterQuotes(key.key())) ? removeOuterQuotes(key.key()) : key.key();\n\t\t// Typesense field names are bare identifiers in filter_by syntax\n\t\t// (field_name:value) with no escaping mechanism. Validate that the\n\t\t// identifier contains only safe characters to prevent filter injection.\n\t\tfor (int i = 0; i < identifier.length(); i++) {\n\t\t\tchar c = identifier.charAt(i);\n\t\t\tif (!Character.isLetterOrDigit(c) && c != '_' && c != '.' && c != '-') {","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/vector-stores/spring-ai-typesense-store/src/main/java/org/springframework/ai/vectorstore/typesense/TypesenseFilterExpressionConverter.java#L34-L70","documentation":"The Typesense filter expression converter maps each Filter.ExpressionType to a filter_by operator string. If the expression type falls outside the supported switch cases (AND, OR, EQ, NE, LT, LTE, GT, GTE, IN, NIN), getOperationSymbol throws a RuntimeException with 'Not supported expression type:'. Typesense's filter_by syntax cannot represent the unsupported operator.","triggerScenarios":"Passing a Filter.Expression with an operator Typesense doesn't map (currently none outside the standard set, but any new/unsupported type such as an unrecognized enum value reaches the default branch) via TypesenseVectorStore similaritySearch or the converter directly.","commonSituations":"Spring AI version upgrades introducing new Filter.ExpressionType values not yet handled by the converter; custom expression types from wrapper libraries; misuse of the converter API with hand-built expressions.","solutions":["Check which expression type you are passing and rewrite the filter using only supported operators (AND, OR, EQ, NE, LT, LTE, GT, GTE, IN, NIN).","Upgrade or patch spring-ai-typesense-store if a newly added Filter.ExpressionType should be supported.","Pre-validate expression types before calling the converter/store and reject unsupported ones with a clear error."],"exampleFix":"// before\nvar expr = new Filter.Expression(Filter.ExpressionType.CONTAINS, new Key(\"title\"), new Value(\"ai\"));\n// after\nvar expr = new Filter.Expression(Filter.ExpressionType.EQ, new Key(\"title\"), new Value(\"ai\"));","handlingStrategy":"validation","validationCode":"Set<Filter.ExpressionType> SUPPORTED = Set.of(AND, OR, EQ, NE, LT, LTE, GT, GTE, IN, NIN); if (!SUPPORTED.contains(expr.type())) throw new IllegalArgumentException(\"Typesense cannot filter on \" + expr.type());","typeGuard":null,"tryCatchPattern":"try { converter.convertExpression(expr); } catch (RuntimeException e) { if (e.getMessage().startsWith(\"Not supported expression type\")) { /* fall back to in-memory filtering or another store */ } else throw e; }","preventionTips":["Restrict generated filters to the documented supported operators","After Spring AI upgrades, re-check for new Filter.ExpressionType values","Centralize filter construction so unsupported operators are rejected early"],"tags":["vector-store","filter-expression","typesense","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-23T08:17:48.524Z"}