apple/pkl · error · ParseException

digit

Error message

digit

What it means

A JSON number must start with at least one decimal digit after the optional minus sign, and leading zeros are not allowed (readDigit's first result is checked; if the first digit is '0', no further digits may follow it). readNumber throws expected("digit") when the character after '-' (or at the number's start) is not a digit — e.g. "-", "-x", or ".5" where a number was expected.

Source

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

          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();
    handler.endNumber(endCapture());
  }

  @SuppressWarnings("UnusedReturnValue")
  private boolean readFraction() throws IOException {
    if (!readChar('.')) {
      return false;
    }
    if (!readDigit()) {
      throw expected("digit");
    }

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Write the number with a leading digit: 0.5 instead of .5, and ensure '-' is followed by digits.
  2. Replace NaN/Infinity with null or strings — they are not valid JSON numbers.
  3. Check templating: if a variable failed to interpolate, the value position may be empty or a lone '-'.
  4. Catch ParseException and use its position to inspect the malformed number token.

Example fix

// before
String json = "{\"ratio\": .5}"; // no leading digit
// after
String json = "{\"ratio\": 0.5}";
Defensive patterns

Strategy: validation

Validate before calling

// Java: reject numbers lacking a leading digit before parsing
if (java.util.regex.Pattern.compile("(^|[\\[,\\s:])(-?)(\\.\\D|[-.]\\s*[,}\\]])").matcher(json).find()) {
  throw new IllegalArgumentException("JSON numbers require at least one leading digit (0.5 not .5)");
}

Try / catch

try {
  parser.parse(json);
} catch (ParseException e) {
  if (e.getMessage().contains("digit")) {
    throw new IllegalArgumentException("Malformed JSON number at " + e.getLocation().line + ":" + e.getLocation().column + " — a digit was required", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: parse() on inputs like "{\"n\": -}" (dangling minus), "{\"n\": .5}" (leading dot), or a value position holding a non-number character, where readValue dispatched to readNumber because of '-' or a digit-like start.

Common situations: Hand-written JSON with .5 instead of 0.5, template variables left empty ("-" with the number interpolated away), NaN/Infinity pasted from JavaScript (not valid JSON numbers), truncated numeric output.

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