{"record":{"id":"6a67d06d653c2709","repo":"google/gson","slug":"failed-parsing-json-source-to-json","errorCode":null,"errorMessage":"Failed parsing JSON source to Json","messagePattern":"Failed parsing JSON source to Json","errorType":"exception","errorClass":"JsonParseException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/JsonStreamParser.java","lineNumber":91,"sourceCode":"  /**\n   * Returns the next available {@link JsonElement} on the reader. Throws a {@link\n   * NoSuchElementException} if no element is available.\n   *\n   * @return the next available {@code JsonElement} on the reader.\n   * @throws JsonParseException if the incoming stream is malformed JSON.\n   * @throws NoSuchElementException if no {@code JsonElement} is available.\n   * @since 1.4\n   */\n  @Override\n  public JsonElement next() throws JsonParseException {\n    if (!hasNext()) {\n      throw new NoSuchElementException();\n    }\n\n    try {\n      return Streams.parse(parser);\n    } catch (StackOverflowError | OutOfMemoryError e) {\n      throw new JsonParseException(\"Failed parsing JSON source to Json\", e);\n    }\n  }\n\n  /**\n   * Returns true if a {@link JsonElement} is available on the input for consumption\n   *\n   * @return true if a {@link JsonElement} is available on the input, false otherwise\n   * @throws JsonParseException if the incoming stream is malformed JSON.\n   * @since 1.4\n   */\n  @Override\n  public boolean hasNext() {\n    synchronized (lock) {\n      try {\n        return parser.peek() != JsonToken.END_DOCUMENT;\n      } catch (MalformedJsonException e) {\n        throw new JsonSyntaxException(e);\n      } catch (IOException e) {","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/google/gson/blob/310ac341f2f92a454b229bf21f70d2d18b2b6db7/gson/src/main/java/com/google/gson/JsonStreamParser.java#L73-L109","documentation":"Thrown by JsonStreamParser.next() when Streams.parse(parser) raises a StackOverflowError or OutOfMemoryError. StackOverflow happens with deeply nested JSON structures; OutOfMemoryError happens when the document (or its in-memory tree representation) exhausts JVM heap. Gson catches these VM errors and wraps them in a JsonParseException because JsonStreamParser builds a full JsonElement tree, making it vulnerable to pathological inputs.","triggerScenarios":"Calling JsonStreamParser.next() (or iterating the parser) on JSON with thousands of nested levels (e.g. [[[[...]]]]) causing StackOverflowError, or on an extremely large document causing OutOfMemoryError during tree construction.","commonSituations":"Processing untrusted or external JSON feeds (JSON bombs), running on JVMs with small -Xss or -Xmx, reading whole documents with JsonStreamParser instead of the streaming JsonReader, legacy code migrating from JsonParser.parse().","solutions":["Switch from JsonStreamParser to streaming JsonReader to avoid building a full in-memory tree and process tokens incrementally","Increase thread stack size (-Xss) if nesting is legitimately deep, or heap (-Xmx) if documents are legitimately large","Validate and limit the size/depth of untrusted JSON before parsing (e.g. check byte length, count bracket depth with a pre-scan)","Sandbox untrusted input: parse with a hardened reader configured with strictness and size caps"],"exampleFix":"// before\nJsonStreamParser parser = new JsonStreamParser(hugeJson);\nJsonElement e = parser.next();\n\n// after - streaming avoids full tree\ntry (JsonReader reader = new JsonReader(new StringReader(json))) {\n  reader.beginArray();\n  while (reader.hasNext()) {\n    handle(reader.nextString());\n  }\n  reader.endArray();\n}","handlingStrategy":"validation","validationCode":"// Pre-check size and depth before parsing untrusted JSON\nString json = readInput();\nif (json.length() > MAX_BYTES) throw new IllegalArgumentException(\"JSON too large: \" + json.length());\nint depth = 0, maxDepth = 0;\nfor (int i = 0; i < json.length(); i++) {\n  char c = json.charAt(i);\n  if (c == '[' || c == '{') { if (++depth > maxDepth) maxDepth = depth; }\n  else if (c == ']' || c == '}') depth--;\n}\nif (maxDepth > MAX_DEPTH) throw new IllegalArgumentException(\"JSON nesting too deep: \" + maxDepth);\n// safe to parse\nJsonElement e = JsonParser.parseString(json);","typeGuard":null,"tryCatchPattern":"try {\n  JsonElement e = parser.next();\n} catch (JsonParseException e) {\n  Throwable cause = e.getCause();\n  if (cause instanceof StackOverflowError) {\n    log.warn(\"JSON nesting too deep\", cause);\n  } else if (cause instanceof OutOfMemoryError) {\n    log.warn(\"JSON document too large\", cause);\n  }\n  throw new MyParseException(\"Unparseable input\", e);\n}","preventionTips":["Prefer streaming JsonReader over JsonStreamParser for untrusted or large input to avoid building full trees","Cap input byte size before handing to Gson","Run JVM with adequate -Xss (stack) and -Xmx (heap) for expected data shapes","Never feed unsanitized external JSON directly to a tree-building parser"],"tags":["json-parsing","memory","stack-overflow","security","oom"],"backgroundTag":null,"analyzedSha":"310ac341f2f92a454b229bf21f70d2d18b2b6db7","analyzedAt":"2026-08-10T02:58:47.455Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}