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
- 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
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
- 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
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
- Attempted to deserialize a java.lang.Class. Forgot to…
- cannot deserialize subtype named ; did you forget to…
- Failed invoking canAccess
- Failed parsing JSON source
- is not accessible and ReflectionAccessFilter does not…
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)