spring-projects/spring-ai · error · RuntimeException
Invalid expression:
Error message
Invalid expression:
What it means
castToExpression converts the parse result into a Filter.Expression. The grammar may yield a Filter.Group or a raw Filter.Value at the top level; only Filter.Expression (and an ungrouped inner expression) are accepted. If the parsed operand is neither, the parser throws RuntimeException("Invalid expression: " + expression). It is thrown from the parser's tree-cast step, meaning the input parsed but has a shape the API cannot return.
Source
Thrown at spring-ai-vector-store/src/main/java/org/springframework/ai/vectorstore/filter/FilterExpressionTextParser.java:325
}
@Override
public Filter.Operand visitLongConstant(FiltersParser.LongConstantContext ctx) {
String text = ctx.getText();
// Remove the trailing 'l' or 'L'
long value = Long.parseLong(text.substring(0, text.length() - 1));
return new Filter.Value(value);
}
public Filter.Expression castToExpression(Filter.Operand expression) {
if (expression instanceof Filter.Group group) {
// Remove the top-level grouping.
return group.content();
}
else if (expression instanceof Filter.Expression exp) {
return exp;
}
throw new RuntimeException("Invalid expression: " + expression);
}
}
public static class DescriptiveErrorListener extends BaseErrorListener {
public static final DescriptiveErrorListener INSTANCE = new DescriptiveErrorListener();
public final List<String> errorMessages = new CopyOnWriteArrayList<>();
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine,
String msg, RecognitionException e) {
String sourceName = recognizer.getInputStream().getSourceName();
var errorMessage = String.format("Source: %s, Line: %s:%s, Error: %s", sourceName, line, charPositionInLine,
msg);View on GitHub (pinned to 98a7beda4f)
Solutions
- Provide a complete boolean filter expression (identifier OP value, optionally combined with AND/OR/NOT) instead of a bare literal or value
- Check the input string is non-empty and syntactically a full expression, e.g. "country == 'BG'"
- Catch RuntimeException from parse() and show a filter-syntax validation message to the user
- Build the Filter.Expression tree programmatically to avoid string-parse ambiguity
Example fix
// before
parser.parse("'red'");
// after
parser.parse("color == 'red'"); Defensive patterns
Strategy: validation
Validate before calling
if (filterText == null || filterText.isBlank() || !filterText.matches(".*[<>=!].*")) throw new IllegalArgumentException("Filter must be a full expression"); Try / catch
try { filter = parser.parse(text); }
catch (RuntimeException e) { log.warn("Invalid filter expression: {}", text, e); filter = null; } Prevention
- Always include an operator and identifier in filter text
- Never pass bare literals as filters
- Unit-test filter strings you generate
When it happens
Trigger: Parsing a filter string whose result is a bare value or an empty/odd group rather than a boolean expression, e.g. parse("'red'") or a string that only produces a group node the cast cannot unwrap, via visitGroupExpression -> castToExpression.
Common situations: LLM-generated filter strings that are just a literal value; partially deleted filter text; passing a search-term string where a boolean filter expression is expected.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Unknown compare operator:
- Unsupported operand type:
- Expression of type %s requires a left operand
- Expression of type %s requires a right operand
- Expected a Key operand but got:
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/d485839ba5445e88.
Report an issue: GitHub.