apple/pkl · error · ParseException

hexadecimal digit

Error message

hexadecimal digit

What it means

A \u escape in a JSON string must be followed by exactly four hexadecimal digits. readEscape reads 4 characters after \u and calls isHexDigit on each; the first non-hex character (or EOF) triggers expected("hexadecimal digit"). Common with truncated \u escapes or typos like \u12g4.

Solutions

  1. Complete the escape with exactly 4 hex digits, e.g. \u00e9 instead of \ue or \u12.
  2. If the character is basic ASCII, drop the escape entirely and write the character directly.
  3. Check for template interpolation colliding with the escape sequence and re-order interpolation/escaping.
  4. Catch ParseException and use the reported position to inspect the malformed \u sequence.

Example fix

// before
String json = "{\"ch\": \"\\u12\"}"; // incomplete escape
// after
String json = "{\"ch\": \"\\u0012\"}";
Defensive patterns

Strategy: validation

Validate before calling

// Java: find malformed \u escapes before parsing
if (java.util.regex.Pattern.compile("\\\\u(?![0-9a-fA-F]{4})").matcher(json).find()) {
  throw new IllegalArgumentException("\\u escape must be followed by exactly 4 hex digits");
}

Try / catch

try {
  parser.parse(json);
} catch (ParseException e) {
  if (e.getMessage().contains("hexadecimal digit")) {
    throw new IllegalArgumentException("Malformed \\uXXXX escape at " + e.getLocation().line + ":" + e.getLocation().column, e);
  }
  throw e;
}

Prevention

When it happens

Trigger: parse() on strings containing "\u12", "\uABCG", "\u{" (template variable eaten by the escape), or a string boundary cutting the escape short.

Common situations: Hand-escaped unicode in config files, templating engines interpolating into the middle of a \u escape, truncated transfer of JSON over a size-limited channel, regex/string processing that mangled escape sequences.

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

Appendix: source

Thrown at pkl-core/src/main/java/org/pkl/core/util/json/JsonParser.java:282

    read();
    return string;
  }

  private void readEscape() throws IOException {
    read();
    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");
    }

View on GitHub (pinned to f3efcbfc9b)