{"record":{"id":"ed24820ffee61623","repo":"spring-projects/spring-ai","slug":"filterexpressionparseexception-message-aggregated","errorCode":null,"errorMessage":"FilterExpressionParseException (message aggregated from parse error listener)","messagePattern":"FilterExpressionParseException \\(message aggregated from parse error listener\\)","errorType":"exception","errorClass":"FilterExpressionParseException","httpStatus":null,"severity":"error","filePath":"spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/FilterExpressionTextParser.java","lineNumber":162,"sourceCode":"\t\tparser.removeErrorListeners();\n\t\tthis.errorListener.errorMessages.clear();\n\t\tparser.addErrorListener(this.errorListener);\n\n\t\tif (this.errorHandler != null) {\n\t\t\tparser.setErrorHandler(this.errorHandler);\n\t\t}\n\n\t\tvar filterExpressionVisitor = new FilterExpressionVisitor();\n\t\ttry {\n\t\t\tFilter.Operand operand = filterExpressionVisitor.visit(parser.where());\n\t\t\tvar filterExpression = filterExpressionVisitor.castToExpression(operand);\n\t\t\tthis.cache.putIfAbsent(textFilterExpression, filterExpression);\n\t\t\treturn filterExpression;\n\t\t}\n\t\tcatch (ParseCancellationException e) {\n\t\t\tvar msg = String.join(\"\", this.errorListener.errorMessages);\n\t\t\tvar rootCause = NestedExceptionUtils.getRootCause(e);\n\t\t\tthrow new FilterExpressionParseException(msg, rootCause);\n\t\t}\n\t}\n\n\tpublic void clearCache() {\n\t\tthis.cache.clear();\n\t}\n\n\t/** For testing only */\n\tMap<String, Filter.Expression> getCache() {\n\t\treturn this.cache;\n\t}\n\n\tpublic static class FilterExpressionParseException extends RuntimeException {\n\n\t\tpublic FilterExpressionParseException(String message, @Nullable Throwable cause) {\n\t\t\tsuper(message, cause);\n\t\t}\n","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/FilterExpressionTextParser.java#L144-L180","documentation":"FilterExpressionTextParser.parse() converts a filter expression string into a Filter.Expression using an ANTLR parser. On ParseCancellationException, it aggregates messages collected by its error listener and throws FilterExpressionParseException with the joined message and root cause. This is the standard failure for syntactically invalid filter strings.","triggerScenarios":"Passing a malformed filter string to SearchRequest.builder().filterExpression(\"...\"): unbalanced quotes/brackets, unknown tokens, invalid operators (e.g. \"color eq 'green'\" lowercase), missing operands.","commonSituations":"Filters built by string concatenation from user input; locale/formatting mistakes; typos in field names or operators; upgrading Spring AI and using removed syntax.","solutions":["Fix the filter string syntax to match the Spring AI filter grammar (==, !=, >, IN, AND, OR, brackets).","Use FilterExpressionBuilder programmatic API to avoid string parsing entirely.","Catch FilterExpressionParseException and surface the aggregated error message to identify the offending token.","Call clearCache()/verify cache behavior if a previously cached bad expression persists."],"exampleFix":"// before\nString filter = \"color == green\"; // unquoted value\n// after\nString filter = \"color == 'green'\";","handlingStrategy":"try-catch","validationCode":"boolean looksParseable(String f) {\n    return f != null\n        && f.chars().filter(c -> c == '\\'' || c == '\"').count() % 2 == 0\n        && f.chars().filter(c -> c == '[').count() == f.chars().filter(c -> c == ']').count();\n}","typeGuard":null,"tryCatchPattern":"try {\n    Filter.Expression f = new FilterExpressionTextParser().parse(filterText);\n    request = SearchRequest.builder().filterExpression(f).build();\n} catch (FilterExpressionParseException ex) {\n    log.warn(\"Bad filter '{}': {}\", filterText, ex.getMessage());\n    // fall back to unfiltered search or reject input\n}","preventionTips":["Test filter strings against the documented grammar before shipping","Prefer programmatic FilterExpressionBuilder for user-derived filters","Validate quotes and brackets are balanced in generated filters"],"tags":["vector-store","filter-expression","parse-error","antlr","spring-ai"],"backgroundTag":"invalid-argument-format","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"}