{"record":{"id":"b5364beae321c979","repo":"json-path/JsonPath","slug":"could-not-find-matching-close-quote-for-s-when-pa","errorCode":null,"errorMessage":"Could not find matching close quote for %s when parsing : %s","messagePattern":"Could not find matching close quote for (.+?) when parsing : (.+?)","errorType":"validation","errorClass":"InvalidPathException","httpStatus":null,"severity":"error","filePath":"json-path/src/main/java/com/jayway/jsonpath/internal/CharacterIndex.java","lineNumber":103,"sourceCode":"            readPosition++;\n        }\n        return -1;\n    }\n\n    public int indexOfMatchingCloseChar(int startPosition, char openChar, char closeChar, boolean skipStrings, boolean skipRegex) {\n        if(charAt(startPosition) != openChar){\n            throw new InvalidPathException(\"Expected \" + openChar + \" but found \" + charAt(startPosition));\n        }\n\n        int opened = 1;\n        int readPosition = startPosition + 1;\n        while (inBounds(readPosition)) {\n            if (skipStrings) {\n                char quoteChar = charAt(readPosition);\n                if (quoteChar == SINGLE_QUOTE || quoteChar == DOUBLE_QUOTE){\n                    readPosition = nextIndexOfUnescaped(readPosition, quoteChar);\n                    if(readPosition == -1){\n                        throw new InvalidPathException(\"Could not find matching close quote for \" + quoteChar + \" when parsing : \" + charSequence);\n                    }\n                    readPosition++;\n                }\n            }\n            if (skipRegex) {\n                if (charAt(readPosition) == REGEX) {\n                    readPosition = nextIndexOfUnescaped(readPosition, REGEX);\n                    if(readPosition == -1){\n                        throw new InvalidPathException(\"Could not find matching close for \" + REGEX + \" when parsing regex in : \" + charSequence);\n                    }\n                    readPosition++;\n                }\n            }\n            if (charAt(readPosition) == openChar) {\n                opened++;\n            }\n            if (charAt(readPosition) == closeChar) {\n                opened--;","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/json-path/JsonPath/blob/62a4c9f0f65ba3f625aa0867d64c528ba72d09ec/json-path/src/main/java/com/jayway/jsonpath/internal/CharacterIndex.java#L85-L121","documentation":"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.","triggerScenarios":"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\".","commonSituations":"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.","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."],"exampleFix":"// before\nString path = \"$[?(@.name == '\" + name + \")]\"; // name = O'Brien -> unterminated quote\n// after\nString path = \"$[?(@.name == '\" + name.replace(\"'\", \"\\\\'\") + \")]\";","handlingStrategy":"validation","validationCode":"long singles = path.chars().filter(c -> c == '\\'').count();\nlong doubles = path.chars().filter(c -> c == '\"').count();\nif (singles % 2 != 0 || doubles % 2 != 0) throw new IllegalArgumentException(\"Unbalanced quotes in path: \" + path);\nJsonPath.compile(path); // full syntax check before use","typeGuard":null,"tryCatchPattern":"try {\n    return JsonPath.read(document, path);\n} catch (InvalidPathException e) {\n    log.error(\"Malformed path (unclosed quote?): {}\", path, e);\n    throw new IllegalArgumentException(\"Invalid JSON path\", e);\n}","preventionTips":["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"],"tags":["json-path","path-parsing","unterminated-string","invalid-path"],"backgroundTag":"invalid-json-response","analyzedSha":"62a4c9f0f65ba3f625aa0867d64c528ba72d09ec","analyzedAt":"2026-09-11T11:36:00.448Z","contentChangedAt":"2026-09-11T11:36:00.448Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}