json-path/JsonPath · error · InvalidPathException
Filter must start with '[?(' and end with ')]'.
Error message
Filter must start with '[?(' and end with ')]'. What it means
After '[?' is accepted, FilterCompiler trims and requires the next character to be '(' and the last character of the trimmed string to be ')'. Filters must be fully parenthesized: '[?(<expression>)]'. Unbalanced or missing parentheses throw this InvalidPathException.
Source
Thrown at json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java:72
return new CompiledFilter(compiler.compile());
}
private FilterCompiler(String filterString) {
filter = new CharacterIndex(filterString);
filter.trim();
if (!filter.currentCharIs('[') || !filter.lastCharIs(']')) {
throw new InvalidPathException("Filter must start with '[' and end with ']'. " + filterString);
}
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());
}View on GitHub (pinned to 62a4c9f0f6)
Solutions
- Ensure the predicate is wrapped in a balanced parenthesis pair: '[?(' + expr + ')]'
- Count parentheses in nested logical expressions, e.g. '[?(@.a && (@.b || @.c))]'
- When building dynamically, encapsulate in one helper that always emits the full '[?(...)]' wrapper
- Compile the path in a test to catch the truncation early
Example fix
// before
JsonPath.compile("$..book[?@.price < 10]");
// after
JsonPath.compile("$..book[?(@.price < 10)]"); Defensive patterns
Strategy: validation
Validate before calling
static boolean isParenthesizedFilter(String filter) {
String t = filter == null ? "" : filter.trim();
return t.startsWith("[?(" ) && t.endsWith(")]");
} Type guard
boolean balancedParens(String expr) {
int d = 0;
for (char c : expr.toCharArray()) { if (c=='(') d++; if (c==')') d--; if (d<0) return false; }
return d == 0;
} Try / catch
try {
return JsonPath.compile(path);
} catch (InvalidPathException e) {
throw new IllegalArgumentException("Filter must be '[?(...)]', got: " + path, e);
} Prevention
- Wrap every predicate in a balanced '( ... )' pair inside '[?...]','...']
- For nested boolean logic, count parentheses or build with Criteria API which manages grouping
- Avoid manual string splicing of predicate fragments
When it happens
Trigger: A filter like '[?@.price < 10)]' or '[?(@.price < 10]' (missing closing paren or bracket), produced by string concatenation where only one side of the predicate wrapper was added.
Common situations: Dynamic query building where '(' was added but ')]' truncated; copying a partial expression from a log; nested parentheses miscounted so the final ')' is missing.
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
- Filter must start with '[' and end with ']'.
- Filter must start with '[?' and end with ']'.
- Failed to parse operator
- Filter operator is not supported!
- Could not find matching close quote for %s when parsing : %s
AI-assisted analysis of json-path/JsonPath@62a4c9f0f6 (2026-09-11).
Data as JSON: /api/errors/7357b55848522373.
Report an issue: GitHub.