google/gson · error · MalformedJsonException

Nesting limit {} reached{}

Error message

Nesting limit {} reached{}

What it means

Thrown by JsonReader.push() (JsonReader.java:1492-1497) when opening a new array or object would exceed the configured nesting limit (default 255). The guard stackSize - 1 >= nestingLimit fires inside beginArray/beginObject (and during skipValue) to stop unbounded recursion, protecting recursive TypeAdapter implementations from StackOverflowError. It is a MalformedJsonException carrying locationString() for context.

Source

Thrown at gson/src/main/java/com/google/gson/stream/JsonReader.java:1495

          pos += peekedNumberLength;
          break;
        case PEEKED_EOF:
          // Do nothing
          return;
        default:
          // For all other tokens there is nothing to do; token has already been consumed from
          // underlying reader
      }
      peeked = PEEKED_NONE;
    } while (count > 0);

    pathIndices[stackSize - 1]++;
  }

  private void push(int newTop) throws MalformedJsonException {
    // - 1 because stack contains as first element either EMPTY_DOCUMENT or NONEMPTY_DOCUMENT
    if (stackSize - 1 >= nestingLimit) {
      throw new MalformedJsonException(
          "Nesting limit " + nestingLimit + " reached" + locationString());
    }

    if (stackSize == stack.length) {
      int newLength = stackSize * 2;
      stack = Arrays.copyOf(stack, newLength);
      pathIndices = Arrays.copyOf(pathIndices, newLength);
      pathNames = Arrays.copyOf(pathNames, newLength);
    }
    stack[stackSize++] = newTop;
  }

  /**
   * Returns true once {@code limit - pos >= minimum}. If the data is exhausted before that many
   * characters are available, this returns false.
   */
  private boolean fillBuffer(int minimum) throws IOException {
    char[] buffer = this.buffer;

View on GitHub (pinned to 310ac341f2)

Solutions

  1. Raise the limit with setNestingLimit to match the maximum expected depth.
  2. If the depth is unexpected, validate/reject the payload upstream rather than relying on the parser.
  3. For untrusted input, keep a deliberately low limit and treat MalformedJsonException as a 400/rejection.
  4. Inspect locationString() in the exception to find the offending nesting level.

Example fix

// before
JsonReader r = new JsonReader(reader);
r.setNestingLimit(2);
r.beginArray(); // fails on [{"a":[true]}]

// after
JsonReader r = new JsonReader(reader);
r.setNestingLimit(255);
r.beginArray();
Defensive patterns

Strategy: validation

Validate before calling

int maxExpected = 64; // tune to your schema
reader.setNestingLimit(maxExpected);
try {
  reader.beginArray();
  ...
} catch (MalformedJsonException e) {
  // map to a 400 / domain error
}

Type guard

static boolean withinExpectedDepth(int current, int limit) {
  return current <= limit;
}

Try / catch

try {
  parse(reader);
} catch (MalformedJsonException e) {
  if (e.getMessage().contains("Nesting limit")) return Result.tooDeep();
  throw e;
}

Prevention

When it happens

Trigger: Parsing deeply nested JSON such as [[[[...]]]] beyond the limit; a malicious or buggy payload designed to exhaust the stack; a low nesting limit set via setNestingLimit combined with legitimately nested data; recursive adapters that delegate through many levels.

Common situations: Security-sensitive endpoints parsing untrusted JSON (raise or lower the limit accordingly); tightening the limit for a known-shallow schema and then receiving deeper data; third-party feeds with arbitrary nesting; regression after raising depth expectations.

Related errors


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