{"record":{"id":"2aebd84d931d4ea1","repo":"spring-projects/spring-ai","slug":"not-supported-expression-type-2aebd8","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-neo4j-store/src/main/java/org/springframework/ai/vectorstore/neo4j/filter/Neo4jVectorFilterExpressionConverter.java","lineNumber":64,"sourceCode":"\t\t\tcontext.append(this.getOperationSymbol(expression));\n\t\t\tthis.convertOperand(expression.right(), context);\n\t\t}\n\t}\n\n\tprivate String getOperationSymbol(Expression exp) {\n\t\treturn switch (exp.type()) {\n\t\t\tcase AND -> \" AND \";\n\t\t\tcase OR -> \" OR \";\n\t\t\tcase EQ -> \" = \";\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 \";\n\t\t\tcase NOT, NIN -> \" NOT \";\n\t\t\t// you never know what the future might bring\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 doNot(Expression expression, StringBuilder context) {\n\t\tFilter.ExpressionType expressionType = expression.type();\n\t\t// should not happen, but better safe than sorry\n\t\tif (expressionType != Filter.ExpressionType.NOT) {\n\t\t\tthrow new RuntimeException(\n\t\t\t\t\t\"Unsupported expression type %s. Only NOT is supported here\".formatted(expressionType));\n\t\t}\n\n\t\t// explicitly prefix the embedded expression with NOT\n\t\tcontext.append(\"NOT \").append(this.convertOperand(expression.left()));\n\t}\n\n\t@Override\n\tprotected void doKey(Key key, StringBuilder context) {","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/vector-stores/spring-ai-neo4j-store/src/main/java/org/springframework/ai/vectorstore/neo4j/filter/Neo4jVectorFilterExpressionConverter.java#L46-L82","documentation":"Neo4jVectorFilterExpressionConverter.getOperationSymbol switches over Filter.ExpressionType and throws a RuntimeException for any type it has no Cypher operator mapping for (default branch). This means a filter expression containing an expression type the Neo4j converter does not support was passed to the store for a similarity search with a filter.","triggerScenarios":"Passing a SearchRequest whose filter expression uses an ExpressionType not mapped in the switch (e.g. NIN combined semantics, or a new type added to Filter in a newer Spring AI version) to Neo4jVectorStore.similaritySearch.","commonSituations":"Building complex filters programmatically with NOT/NIN and hitting an unhandled branch; upgrading Spring AI where new ExpressionType values were added but this converter was not updated; hand-rolled Filter.Expression trees containing unsupported nodes.","solutions":["Rewrite the filter expression using only supported types (AND, OR, EQ, NE, LT, LTE, GT, GTE, IN, NOT, NIN).","Replace NIN with a negated IN via NOT to keep within supported symbols.","Check the Spring AI version; upgrade or downgrade so converter and Filter.ExpressionType are in sync.","Contribute/implement the missing case in getOperationSymbol if a new expression type is needed."],"exampleFix":"// before\nnew Filter.Expression(ExpressionType.NOT, new In(\"tag\", List.of(\"x\")), null); // unhandled combination\n// after\nnew Filter.Nin(\"tag\", List.of(\"x\")); // maps to the supported \" NOT \" symbol","handlingStrategy":"validation","validationCode":"static boolean isSupported(Filter.Expression exp) {\n    return switch (exp.type()) {\n        case AND, OR, EQ, NE, LT, LTE, GT, GTE, IN, NOT, NIN -> true;\n        default -> false;\n    };\n}\n// check recursively before similaritySearch","typeGuard":null,"tryCatchPattern":"try {\n    vectorStore.similaritySearch(request);\n} catch (RuntimeException e) {\n    if (e.getMessage().startsWith(\"Not supported expression type\")) {\n        // fall back to unfiltered search and post-filter\n    }\n}","preventionTips":["Only build filters from the supported ExpressionType set for this converter","Prefer builder methods (Filter.eq, Filter.in) over raw Expression constructors","After Spring AI upgrades, re-check converter supported types","Add a recursive filter-tree validator before hitting the store"],"tags":["neo4j","filter-expression","unsupported-operation"],"backgroundTag":"unsupported-enum-value","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"}