{"record":{"id":"2ef037b9c2bb59e3","repo":"apple/pkl","slug":"nesting-too-deep","errorCode":null,"errorMessage":"Nesting too deep","messagePattern":"Nesting too deep","errorType":"exception","errorClass":"ParseException","httpStatus":null,"severity":"error","filePath":"pkl-core/src/main/java/org/pkl/core/util/json/JsonParser.java","lineNumber":147,"sourceCode":"\n  private void readValue() throws IOException {\n    switch (current) {\n      case 'n' -> readNull();\n      case 't' -> readTrue();\n      case 'f' -> readFalse();\n      case '\"' -> readString();\n      case '[' -> readArray();\n      case '{' -> readObject();\n      case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> readNumber();\n      default -> throw expected(\"value\");\n    }\n  }\n\n  private void readArray() throws IOException {\n    var array = handler.startArray();\n    read();\n    if (++nestingLevel > MAX_NESTING_LEVEL) {\n      throw error(\"Nesting too deep\");\n    }\n    skipWhiteSpace();\n    if (readChar(']')) {\n      nestingLevel--;\n      handler.endArray(array);\n      return;\n    }\n    do {\n      skipWhiteSpace();\n      handler.startArrayValue(array);\n      readValue();\n      handler.endArrayValue(array);\n      skipWhiteSpace();\n    } while (readChar(','));\n    if (!readChar(']')) {\n      throw expected(\"',' or ']'\");\n    }\n    nestingLevel--;","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-core/src/main/java/org/pkl/core/util/json/JsonParser.java#L129-L165","documentation":"Pkl's JSON parser enforces MAX_NESTING_LEVEL on arrays (and objects): when the nesting level of nested `[` exceeds the maximum, parsing aborts with 'Nesting too deep'. This guards both the parser and the Truffle interpreter against stack exhaustion from hostile or accidental deeply nested JSON.","triggerScenarios":"Calling `json.parse` on a document with arrays nested beyond MAX_NESTING_LEVEL, e.g. `[[[[[...]]]]]` generated recursively or by adversarial input. Raised in JsonParser.readArray immediately after incrementing nestingLevel.","commonSituations":"Parsing auto-generated JSON from recursive data structures (linked lists encoded as nested arrays); fuzzed or malicious payloads; runaway serialization bugs producing self-nesting output.","solutions":["Flatten or restructure the data before serializing/parsing (avoid encoding recursion as nesting)","Increase/patch the MAX_NESTING_LEVEL constant if your legitimate data is deeply nested (library rebuild)","Reject overly deep input upstream with a quick depth check before parsing","Fix the producer bug that serializes cyclic/recursive structures as unbounded nesting"],"exampleFix":"// before\nval = json.parse(deepNestedJson)  // 1000 levels\n// after\nassert(depth(deepNestedJson) < 100)\nval = json.parse(deepNestedJson)","handlingStrategy":"validation","validationCode":"// cheap depth check on brackets before parsing\ndepth = 0; max = 0\ntext.chars.forEach((c) -> {\n  if (c == '[' || c == '{') { depth++; max = Math.max(max, depth) }\n  else if (c == ']' || c == '}') depth--\n})\nrequire(max < 100, \"JSON nesting too deep\")","typeGuard":null,"tryCatchPattern":"try {\n  value = json.parse(text)\n} catch (e) {\n  if (e.message.contains(\"Nesting too deep\")) throw(\"rejecting overly deep JSON input\")\n  throw e\n}","preventionTips":["Bound the nesting depth of serialized data at the producer","Sanitize untrusted JSON with a depth limit before parsing","Refactor recursive structures into flat, referenced forms"],"tags":["json","pkl","parser","nesting-limit","security-limit"],"backgroundTag":"json-parse-error","analyzedSha":"f3efcbfc9b60d30053b0536d664948d7aa1b8673","analyzedAt":"2026-09-08T13:10:45.570Z","contentChangedAt":"2026-09-08T13:10:45.570Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}