json-path/JsonPath · error · InvalidPathException
Could not find matching close quote for %s when parsing : %s
Error message
Could not find matching close quote for %s when parsing : %s
What it means
CharacterIndex.indexOfMatchingCloseChar scans a JSON path string for the bracket/paren matching an opening delimiter, optionally skipping over quoted string literals. While skipping strings it calls nextIndexOfUnescaped to find the closing unescaped quote; if none exists before the end of input, it cannot continue parsing and throws InvalidPathException. This means the path has an opening quote without a matching closing quote.
Source
Thrown at json-path/src/main/java/com/jayway/jsonpath/internal/CharacterIndex.java:103
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);
if(readPosition == -1){
throw new InvalidPathException("Could not find matching close for " + REGEX + " when parsing regex in : " + charSequence);
}
readPosition++;
}
}
if (charAt(readPosition) == openChar) {
opened++;
}
if (charAt(readPosition) == closeChar) {
opened--;View on GitHub (pinned to 62a4c9f0f6)
Solutions
- Inspect the path string and add the missing closing quote (match single with single, double with double).
- Escape embedded quotes inside the literal using a backslash (\' or \") or switch the outer quote style so inner quotes need no escape.
- If the path is dynamically built, escape or sanitize interpolated values before embedding them in the path expression.
- Validate the path with JsonPath.compile() in a try/catch during input validation rather than deep inside application logic.
Example fix
// before
String path = "$[?(@.name == '" + name + ")]"; // name = O'Brien -> unterminated quote
// after
String path = "$[?(@.name == '" + name.replace("'", "\\'") + ")]"; Defensive patterns
Strategy: validation
Validate before calling
long singles = path.chars().filter(c -> c == '\'').count();
long doubles = path.chars().filter(c -> c == '"').count();
if (singles % 2 != 0 || doubles % 2 != 0) throw new IllegalArgumentException("Unbalanced quotes in path: " + path);
JsonPath.compile(path); // full syntax check before use Try / catch
try {
return JsonPath.read(document, path);
} catch (InvalidPathException e) {
log.error("Malformed path (unclosed quote?): {}", path, e);
throw new IllegalArgumentException("Invalid JSON path", e);
} Prevention
- Always escape quotes inside path string literals
- Compile paths once at startup rather than per-request to fail fast
- Sanitize dynamic values interpolated into path literals
- Beware apostrophes in user data embedded in single-quoted filters
When it happens
Trigger: Calling JsonPath.parse/JsonPath.compile/read with a path whose filter or bracket segment contains an opening single or double quote that is never closed with an unescaped matching quote, e.g. "$[?(@.name == 'foo)]" or "$['key".
Common situations: Paths built by string concatenation where interpolated values contain quotes; forgetting to escape a quote inside a filter expression; copy-pasting JSON path examples where a quote was dropped; generating paths dynamically in scripts whose values contain apostrophes (O'Brien) inside single-quoted literals.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
Related errors
- Could not find matching close for %s when parsing regex in :
- Expected character: %c
- Filter must start with '[' and end with ']'.
- Filter must start with '[?' and end with ']'.
- Filter must start with '[?(' and end with ')]'.
AI-assisted analysis of json-path/JsonPath@62a4c9f0f6 (2026-09-11).
Data as JSON: /api/errors/b5364beae321c979.
Report an issue: GitHub.