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

  1. Provide a complete boolean filter expression (identifier OP value, optionally combined with AND/OR/NOT) instead of a bare literal or value
  2. Check the input string is non-empty and syntactically a full expression, e.g. "country == 'BG'"
  3. Catch RuntimeException from parse() and show a filter-syntax validation message to the user
  4. 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

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


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/d485839ba5445e88. Report an issue: GitHub.