flashman
← All guides

JSON depth limits and safe complexity budgets

Protect JSON APIs from deeply nested input by measuring structural complexity, bounding parsers and validators, replacing unsafe recursion, and testing clear limits.

2026-08-31 · 8 min read

  • json
  • api-design
  • performance

JSON size limits control bytes but not structural complexity. A compact chain of nested objects can exhaust a recursive parser, validator, serializer, authorization walker, or logging pipeline long before it reaches an ordinary request-size threshold.

A safe API treats bytes, depth, container count, scalar count, and expensive schema features as separate dimensions. The limits should be deliberate, observable, and consistent enough that clients receive a useful error before application resources are exhausted.

Define a complexity budget

Start from legitimate payloads and set a maximum depth with headroom for expected schema evolution. Add byte and member limits because a shallow object can still be extremely wide, while a deeply nested document can remain deceptively small.

  • Count object and array boundaries using one documented definition.
  • Bound total decoded bytes before schema validation.
  • Limit arrays and object members where the domain has natural caps.
  • Return a stable client error without echoing the full payload.

Apply limits at every representation boundary

A gateway may enforce compressed request bytes while the application sees a much larger decoded body. The parser, schema library, domain mapper, database serializer, and response encoder can each have independent recursion or allocation behavior.

Reject excessive compressed and decoded sizes, then enforce structure while parsing or immediately afterward. Avoid fully materializing and repeatedly copying an already-rejected tree merely to calculate its depth.

Make application traversal stack-safe

When legitimate input approaches language call-stack limits, traverse with an explicit stack and a visited-work counter. JSON values do not contain cycles after parsing, but application objects created from them might, so serializers still need cycle handling.

  • Keep schema recursion bounded even for self-referential domain models.
  • Avoid deep-clone and generic merge utilities on untrusted trees.
  • Cap error collection so one payload cannot create thousands of messages.
  • Redact sensitive leaves before any diagnostic summary.

Verify limits with controlled fixtures

Use Flashman's JSON formatter to inspect synthetic trees, diff tool to reduce a failing structure, units converter for byte budgets, case converter to identify repeated generated wrappers, and hash tool to label fixtures without storing their full contents.

Test depth and width independently just below, at, and above each boundary. Include compressed requests, malformed closing delimiters, schema references, error reporting, logging, and the exact parser and runtime configuration deployed in production.

Try these tools