json-path/JsonPath · error · InvalidPathException
Expected end of filter expression instead of: %s
Error message
Expected end of filter expression instead of: %s
What it means
FilterCompiler.compile() parses the filter expression and then skips blanks; if any characters remain within the '[?(...)]' envelope, the expression is malformed and this InvalidPathException is thrown, naming the leftover text. It means the filter body contained extra tokens after a complete logical expression, e.g. '[?(@.a == 1) @.b]'.
Source
Thrown at json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java:81
filter.incrementPosition(1);
filter.decrementEndPosition(1);
filter.trim();
if (!filter.currentCharIs('?')) {
throw new InvalidPathException("Filter must start with '[?' and end with ']'. " + filterString);
}
filter.incrementPosition(1);
filter.trim();
if (!filter.currentCharIs('(') || !filter.lastCharIs(')')) {
throw new InvalidPathException("Filter must start with '[?(' and end with ')]'. " + filterString);
}
}
public Predicate compile() {
try {
final ExpressionNode result = readLogicalOR();
filter.skipBlanks();
if (filter.inBounds()) {
throw new InvalidPathException(String.format("Expected end of filter expression instead of: %s",
filter.subSequence(filter.position(), filter.length())));
}
return result;
} catch (InvalidPathException e){
throw e;
} catch (Exception e) {
throw new InvalidPathException("Failed to parse filter: " + filter + ", error on position: " + filter.position() + ", char: " + filter.currentChar());
}
}
private ValueNode readValueNode() {
switch (filter.skipBlanks().currentChar()) {
case DOC_CONTEXT : return readPath();
case EVAL_CONTEXT : return readPath();
case NOT:
filter.incrementPosition(1);
switch (filter.skipBlanks().currentChar()) {View on GitHub (pinned to 62a4c9f0f6)
Solutions
- Inspect the leftover text in the message — it points at exactly where the valid expression ends
- Combine predicates with Filter.and(Filter, Filter) or Criteria instead of concatenating '[?...] ' strings
- Check for early-closing characters (a stray ')' or quote) that end the expression prematurely
- Split the path into a base path plus a single '[?(...)]' filter; only one filter per bracket pair is allowed
Example fix
// before
JsonPath.compile("$..book[?(@.a == 1) @.b == 2]");
// after
JsonPath.compile("$..book[?(@.a == 1 && @.b == 2)]"); Defensive patterns
Strategy: validation
Validate before calling
static boolean singleFilterExpression(String path) {
return path != null && path.indexOf("[?") == path.lastIndexOf("[?"); // one filter per path segment string
} Try / catch
try {
return JsonPath.compile(path);
} catch (InvalidPathException e) {
if (e.getMessage().startsWith("Expected end of filter expression")) {
throw new IllegalArgumentException("Trailing tokens after filter expression in: " + path, e);
}
throw e;
} Prevention
- Combine predicates with Filter.and()/Filter.or() instead of concatenating '[?...] [?...]' strings
- Keep exactly one expression inside each '[?(...)]' pair
- Check the message's leftover text — it marks where the valid expression ended
- Compile user/config-provided paths at load time, not at query time
When it happens
Trigger: Passing a filter whose inner expression has trailing junk after a parseable expression — extra quotes, an unmatched operand like '[?(@.a == 1 &&)]', duplicated predicates, or concatenated filters '[?(@.a)][?(@.b)]' passed in one string.
Common situations: Merging multiple filter predicates by naive string concatenation instead of using Filter.and()/Filter.filter(); typos leaving stray characters; a quote or bracket closing early so the parser stops mid-string.
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
- Failed to parse filter:
- Filter must start with '[' and end with ']'.
- Filter must start with '[?' and end with ']'.
- Filter must start with '[?(' and end with ')]'.
- Failed to parse operator
AI-assisted analysis of json-path/JsonPath@62a4c9f0f6 (2026-09-11).
Data as JSON: /api/errors/38da6648881533e7.
Report an issue: GitHub.