json-path/JsonPath · error · InvalidPathException

Arguments to function: '' are not closed properly.

Error message

Arguments to function: '' are not closed properly.

What it means

When the compiler scans a function-call token `name(...)`, it tracks parenthesis nesting; if the closing parenthesis is never found before the path string ends, the arguments are considered unclosed and compilation throws InvalidPathException naming the function.

Solutions

  1. Balance the parentheses in the path, e.g. `$.length(` → `$.length()`.
  2. For filters with functions, ensure the whole predicate is closed: `$[?(@.x.length() > 2)]`.
  3. When generating paths in code, count/verify parentheses before compiling, and log the full untruncated path on failure.

Example fix

// before
JsonPath.read(json, "$.items.length(");
// after
JsonPath.read(json, "$.items.length()");
Defensive patterns

Strategy: validation

Validate before calling

boolean parensBalanced(String path) {
    int n = 0;
    for (char c : path.toCharArray()) {
        if (c == '(') n++;
        if (c == ')') n--;
        if (n < 0) return false;
    }
    return n == 0;
}

Try / catch

try {
    return JsonPath.read(json, path);
} catch (InvalidPathException e) {
    throw new IllegalArgumentException("Unclosed function arguments in path: " + path, e);
}

Prevention

When it happens

Trigger: Paths with unbalanced parentheses such as `$.length()` written as `$.length(`, nested calls missing a close like `$.sum((@.x, @.y`, or truncation of a long path string.

Common situations: Hand-written function paths (length, min, max, avg, concat, etc.) with typos; string truncation in logs/configs; generated filter expressions where the closing paren was appended after a conditional that got skipped.

Related errors


AI-assisted analysis of json-path/JsonPath@62a4c9f0f6 (2026-09-11). Data as JSON: /api/errors/7a7c61b95ce79eda. Report an issue: GitHub.

Appendix: source

Thrown at json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java:226

            endPosition = path.length();
        }


        List<Parameter> functionParameters = null;
        if (isFunction) {
            int parenthesis_count = 1;
            for(int i = readPosition + 1; i < path.length(); i++){
                if (path.charAt(i) == CLOSE_PARENTHESIS)
                    parenthesis_count--;
                else if (path.charAt(i) == OPEN_PARENTHESIS)
                    parenthesis_count++;
                if (parenthesis_count == 0)
                    break;
            }

            if (parenthesis_count != 0){
                String functionName = path.subSequence(startPosition, endPosition).toString();
                throw new InvalidPathException("Arguments to function: '" + functionName + "' are not closed properly.");
            }

            if (path.inBounds(readPosition+1)) {
                // read the next token to determine if we have a simple no-args function call
                char c = path.charAt(readPosition + 1);
                if (c != CLOSE_PARENTHESIS) {
                    path.setPosition(endPosition+1);
                    // parse the arguments of the function - arguments that are inner queries or JSON document(s)
                    String functionName = path.subSequence(startPosition, endPosition).toString();
                    functionParameters = parseFunctionParameters(functionName);
                } else {
                    path.setPosition(readPosition + 1);
                }
            }
            else {
                path.setPosition(readPosition);
            }
        }

View on GitHub (pinned to 62a4c9f0f6)