google/gson · error · JsonParseException

Failed parsing JSON source to Json

Error message

Failed parsing JSON source to Json

What it means

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.

Solutions

  1. Switch from JsonStreamParser to streaming JsonReader to avoid building a full in-memory tree and process tokens incrementally
  2. Increase thread stack size (-Xss) if nesting is legitimately deep, or heap (-Xmx) if documents are legitimately large
  3. Validate and limit the size/depth of untrusted JSON before parsing (e.g. check byte length, count bracket depth with a pre-scan)
  4. Sandbox untrusted input: parse with a hardened reader configured with strictness and size caps

Example fix

// before
JsonStreamParser parser = new JsonStreamParser(hugeJson);
JsonElement e = parser.next();

// after - streaming avoids full tree
try (JsonReader reader = new JsonReader(new StringReader(json))) {
  reader.beginArray();
  while (reader.hasNext()) {
    handle(reader.nextString());
  }
  reader.endArray();
}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check size and depth before parsing untrusted JSON
String json = readInput();
if (json.length() > MAX_BYTES) throw new IllegalArgumentException("JSON too large: " + json.length());
int depth = 0, maxDepth = 0;
for (int i = 0; i < json.length(); i++) {
  char c = json.charAt(i);
  if (c == '[' || c == '{') { if (++depth > maxDepth) maxDepth = depth; }
  else if (c == ']' || c == '}') depth--;
}
if (maxDepth > MAX_DEPTH) throw new IllegalArgumentException("JSON nesting too deep: " + maxDepth);
// safe to parse
JsonElement e = JsonParser.parseString(json);

Try / catch

try {
  JsonElement e = parser.next();
} catch (JsonParseException e) {
  Throwable cause = e.getCause();
  if (cause instanceof StackOverflowError) {
    log.warn("JSON nesting too deep", cause);
  } else if (cause instanceof OutOfMemoryError) {
    log.warn("JSON document too large", cause);
  }
  throw new MyParseException("Unparseable input", e);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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().

Related errors


AI-assisted analysis of google/gson@310ac341f2 (2026-08-10). Data as JSON: /api/errors/6a67d06d653c2709. Report an issue: GitHub.

Appendix: source

Thrown at gson/src/main/java/com/google/gson/JsonStreamParser.java:91

  /**
   * Returns the next available {@link JsonElement} on the reader. Throws a {@link
   * NoSuchElementException} if no element is available.
   *
   * @return the next available {@code JsonElement} on the reader.
   * @throws JsonParseException if the incoming stream is malformed JSON.
   * @throws NoSuchElementException if no {@code JsonElement} is available.
   * @since 1.4
   */
  @Override
  public JsonElement next() throws JsonParseException {
    if (!hasNext()) {
      throw new NoSuchElementException();
    }

    try {
      return Streams.parse(parser);
    } catch (StackOverflowError | OutOfMemoryError e) {
      throw new JsonParseException("Failed parsing JSON source to Json", e);
    }
  }

  /**
   * Returns true if a {@link JsonElement} is available on the input for consumption
   *
   * @return true if a {@link JsonElement} is available on the input, false otherwise
   * @throws JsonParseException if the incoming stream is malformed JSON.
   * @since 1.4
   */
  @Override
  public boolean hasNext() {
    synchronized (lock) {
      try {
        return parser.peek() != JsonToken.END_DOCUMENT;
      } catch (MalformedJsonException e) {
        throw new JsonSyntaxException(e);
      } catch (IOException e) {

View on GitHub (pinned to 310ac341f2)