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 confirming the filter starts with '[' and ends with ']', FilterCompiler trims both and requires the first character to be '?'. A filter like '[(@.price < 10)]' (missing the question mark) fails this check and throws this InvalidPathException. Filters in JsonPath must follow the [?(<expression>)] form.

Source

Thrown at json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java:67

    private CharacterIndex filter;

    public static Filter compile(String filterString) {
        FilterCompiler compiler = new FilterCompiler(filterString);
        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;

View on GitHub (pinned to 62a4c9f0f6)

Solutions

  1. Insert '?' after the opening bracket: '[?(...)]' is the required filter form
  2. Do not confuse script expressions '[(@.length-1)]' with filters; if you want a filter, add '?'
  3. Re-check the dialect of any copied JSONPath snippet — Goessner-style docs mix '[?(...)]' and other bracket forms
  4. Validate the path with a quick compile() in a unit test before shipping it in config

Example fix

// before
JsonPath.compile("$..book[(@.price < 10)]");
// after
JsonPath.compile("$..book[?(@.price < 10)]");
Defensive patterns

Strategy: validation

Validate before calling

static boolean isFilterForm(String filter) {
    String t = filter == null ? "" : filter.trim();
    return t.startsWith("[?") && t.endsWith("]");
}

Type guard

boolean hasQuestionMarkFilter(String path) { return path != null && path.matches(".*\\[\\?\\(.*\\)\\].*"); }

Try / catch

try {
    return JsonPath.compile(path);
} catch (InvalidPathException e) {
    if (e.getMessage().contains("must start with '[?'")) {
        throw new IllegalArgumentException("Filter missing '?': use [?(...)] in " + path, e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Passing a filter string like '[(@.x == 1)]' or '[...]' (no '?') to JsonPath.compile(), a path string ending in '[...]' used as a filter predicate, or FilterCompiler.compile via public Path APIs.

Common situations: Confusing script expression syntax '[...]' with filter syntax '[?(...)]' when copying examples from other JSONPath dialects; dropping the '?' during manual editing.

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 json-path/JsonPath@62a4c9f0f6 (2026-09-11). Data as JSON: /api/errors/d0e0b5647b339187. Report an issue: GitHub.