apple/pkl · error · ParseException
valid escape sequence
Error message
valid escape sequence
What it means
JSON strings only allow a fixed set of escapes: \" \\ \/ \b \f \n \r \t and \uXXXX. Any other character after a backslash hits the default branch of readEscape and throws expected("valid escape sequence"). This rejects escapes borrowed from other languages, such as \x41, \0, or \' (escaped single quote).
Solutions
- Replace the unsupported escape with a valid one: use \' -> ', \x41 -> A or \u0041, \0 -> \u0000.
- Re-serialize the data with a real JSON encoder instead of reusing another language's escaping routine.
- Search the input for backslashes and audit each escape against the JSON-allowed set.
- Catch ParseException and use its position to fix the exact offending escape.
Example fix
// before
String json = "{\"quote\": \\"it\\\\'s\\\\"}"; // \' is not a JSON escape
// after
String json = "{\"quote\": \\"it's\\\\"}"; // ' needs no escaping Defensive patterns
Strategy: validation
Validate before calling
// Java: detect escapes outside the JSON-allowed set
if (java.util.regex.Pattern.compile("\\\\(?!\"|\\\\|/|b|f|n|r|t|u)").matcher(json).find()) {
throw new IllegalArgumentException("Invalid JSON escape sequence found");
} Try / catch
try {
parser.parse(json);
} catch (ParseException e) {
if (e.getMessage().contains("valid escape sequence")) {
throw new IllegalArgumentException("Unsupported escape in JSON string at " + e.getLocation().line + ":" + e.getLocation().column + " — only \" \\ / b f n r t u are allowed", e);
}
throw e;
} Prevention
- Only use \" \\ / \b \f \n \r \t \uXXXX in JSON strings.
- Never reuse shell/SQL/JS escaping routines for JSON.
- Escape once, with the correct JSON encoder for your language.
- Audit hand-written config for \' or \x escapes copied from other languages.
When it happens
Trigger: parse() on strings containing \' (common when a tool escapes single quotes), \xNN hex escapes, \0, \e, or backslash-escaped characters invented by custom serializers.
Common situations: Output from non-JSON serializers (shell/SQL string escaping reused for JSON), string escaping performed twice or with the wrong escaping function, hand-written config copying escaping habits from other languages.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
Related errors
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/9cda0ac2d5c58372.
Report an issue: GitHub.
Appendix: source
Thrown at pkl-core/src/main/java/org/pkl/core/util/json/JsonParser.java:288
switch (current) {
case '"', '/', '\\' -> captureBuffer.append((char) current);
case 'b' -> captureBuffer.append('\b');
case 'f' -> captureBuffer.append('\f');
case 'n' -> captureBuffer.append('\n');
case 'r' -> captureBuffer.append('\r');
case 't' -> captureBuffer.append('\t');
case 'u' -> {
var hexChars = new char[4];
for (var i = 0; i < 4; i++) {
read();
if (!isHexDigit()) {
throw expected("hexadecimal digit");
}
hexChars[i] = (char) current;
}
captureBuffer.append((char) Integer.parseInt(new String(hexChars), 16));
}
default -> throw expected("valid escape sequence");
}
read();
}
private void readNumber() throws IOException {
handler.startNumber();
startCapture();
readChar('-');
var firstDigit = current;
if (!readDigit()) {
throw expected("digit");
}
if (firstDigit != '0') {
//noinspection StatementWithEmptyBody
while (readDigit()) {}
}
readFraction();
readExponent();View on GitHub (pinned to f3efcbfc9b)