ComposioHQ/composio · error · ValueError
JSON Schema exceeds maximum nesting depth of {MAX_NODE_DEPTH
Error message
JSON Schema exceeds maximum nesting depth of {MAX_NODE_DEPTH} What it means
to_strict_json_schema's _dedupe_required pass enforces a hard recursion cap (MAX_NODE_DEPTH) on schema node depth. Exceeding it raises ValueError, protecting against pathological or cyclic-ish schemas that would otherwise recurse unboundedly during strict-schema conversion.
Source
Thrown at python/composio/utils/strict_schema.py:189
node_type = node.get("type")
if isinstance(node_type, str):
return node_type == "null"
if isinstance(node_type, list):
return "null" in node_type
if isinstance(node.get("enum"), list):
return None in node["enum"]
if "const" in node:
return node["const"] is None
for keyword in ("anyOf", "oneOf"):
branches = node.get(keyword)
if isinstance(branches, list):
return any(_schema_accepts_null(b, root) for b in branches)
return True
def _dedupe_required(value: t.Any, is_schema: bool = True, depth: int = 0) -> t.Any:
if depth > MAX_NODE_DEPTH:
raise ValueError(
f"JSON Schema exceeds maximum nesting depth of {MAX_NODE_DEPTH}"
)
if isinstance(value, list):
return [_dedupe_required(item, is_schema, depth + 1) for item in value]
if not isinstance(value, dict):
return value
clone: dict[str, t.Any] = {}
for key, child in value.items():
if is_schema and key == "required" and isinstance(child, list):
clone[key] = list(dict.fromkeys(child))
else:
clone[key] = _dedupe_required(
child, is_schema and key not in INSTANCE_VALUE_KEYWORDS, depth + 1
)
return clone
class _Walker:View on GitHub (pinned to 64b1b85502)
Solutions
- Reduce real nesting by using $ref/$defs instead of fully inlined recursive structures
- Check for accidental duplication: a transformation pass that re-wraps the schema each run can multiply depth — diff depth before/after each step
- If legitimately deep, split the schema or raise the limit only if you control the constant and accept the risk
- Sanitize/truncate untrusted schemas before strict conversion
Example fix
# before (recursive inline)
{"type": "object", "properties": {"child": {"type": "object", "properties": {"child": {...deep...}}}}}
# after
{"$defs": {"node": {"type": "object", "properties": {"child": {"$ref": "#/$defs/node"}}}}, "$ref": "#/$defs/node"} Defensive patterns
Strategy: validation
Validate before calling
def schema_depth(v, d=0):
if d > 100: return d
if isinstance(v, dict): return max([schema_depth(x, d+1) for x in v.values()], default=d)
if isinstance(v, list): return max([schema_depth(x, d+1) for x in v], default=d)
return d
assert schema_depth(schema) < MAX_NODE_DEPTH Try / catch
try:
strict = to_strict_json_schema(schema)
except ValueError as e:
if "nesting depth" in str(e):
schema = flatten_with_defs(schema)
strict = to_strict_json_schema(schema) Prevention
- Express recursion with $ref/$defs instead of inlining
- Depth-check untrusted schemas before conversion
- Watch for transformation passes that re-wrap and deepen schemas each run
When it happens
Trigger: Feeding a schema whose nested allOf/properties/items chains exceed the depth limit — deeply recursive definitions, schemas where $ref inlining produced self-nesting, or adversarially deep generated specs.
Common situations: Recursive schemas (trees, linked structures) inlined without $refs; a bug duplicating nested levels on each transformation pass; schemas from untrusted/auto-generated sources; accidental self-referential definitions after refactoring.
Related errors
- JSON Schema nesting too deep to dereference
- Cannot resolve $ref {pointer}
- JSON Schema node depth exceeded cap ({MAX_NODE_DEPTH})
- JSON Schema $ref chain exceeded depth cap ({MAX_REF_CHAIN_DE
- Invalid property type {p_type}: {schema!r}
AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28).
Data as JSON: /api/errors/9055249468c39d38.
Report an issue: GitHub.