json-path/JsonPath · error · InvalidPathException

Expected %s but found %s

Error message

Expected %s but found %s

What it means

CharacterIndex.indexOfMatchingCloseChar locates the closing bracket matching an opening one during path parsing. If the character at startPosition is not the expected opening char (openChar), the path text is malformed and InvalidPathException 'Expected X but found Y' is thrown, naming both characters.

Source

Thrown at json-path/src/main/java/com/jayway/jsonpath/internal/CharacterIndex.java:92

    public int position(){
        return position;
    }

    public int indexOfClosingSquareBracket(int startPosition) {
        int readPosition = startPosition;
        while (inBounds(readPosition)) {
            if(charAt(readPosition) == CLOSE_SQUARE_BRACKET){
                return readPosition;
            }
            readPosition++;
        }
        return -1;
    }

    public int indexOfMatchingCloseChar(int startPosition, char openChar, char closeChar, boolean skipStrings, boolean skipRegex) {
        if(charAt(startPosition) != openChar){
            throw new InvalidPathException("Expected " + openChar + " but found " + charAt(startPosition));
        }

        int opened = 1;
        int readPosition = startPosition + 1;
        while (inBounds(readPosition)) {
            if (skipStrings) {
                char quoteChar = charAt(readPosition);
                if (quoteChar == SINGLE_QUOTE || quoteChar == DOUBLE_QUOTE){
                    readPosition = nextIndexOfUnescaped(readPosition, quoteChar);
                    if(readPosition == -1){
                        throw new InvalidPathException("Could not find matching close quote for " + quoteChar + " when parsing : " + charSequence);
                    }
                    readPosition++;
                }
            }
            if (skipRegex) {
                if (charAt(readPosition) == REGEX) {
                    readPosition = nextIndexOfUnescaped(readPosition, REGEX);

View on GitHub (pinned to 62a4c9f0f6)

Solutions

  1. Print the full path string and visually verify every [ has a matching ].
  2. Count brackets/braces in the path before compiling (a simple balance check catches this).
  3. Fix the malformed segment (add the missing ']' or remove the stray char).
  4. Escape or quote literal brackets inside filter expressions correctly.

Example fix

// before
String path = "$.store.book[?(@.price < 10";
Path p = JsonPath.compile(path);
// after
String path = "$.store.book[?(@.price < 10)]";
Path p = JsonPath.compile(path);
Defensive patterns

Strategy: validation

Validate before calling

long opens = path.chars().filter(c -> c == '[').count();
long closes = path.chars().filter(c -> c == ']').count();
if (opens != closes) throw new IllegalArgumentException("Unbalanced brackets in path: " + path);

Try / catch

try {
    Path p = JsonPath.compile(path);
} catch (InvalidPathException e) {
    throw new IllegalArgumentException("Malformed JSON path '" + path + "': " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: Calling indexOfClosingBracket/indexOfMatchingCloseChar against a path string where the bracket/brace/paren position does not actually hold the expected opening char — e.g. an unclosed or mismatched filter like '$[?(@.a == 1' or '$.store.book[0' during JsonPath.compile/parse.

Common situations: Hand-written JSON path strings with mismatched or missing brackets, braces in filter expressions [?(...)], or programmatically assembled paths where an index segment got dropped.

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/b4a5406356ebd376. Report an issue: GitHub.