ComposioHQ/composio · error · JSONSchemaRefResolutionError
JSON Schema node depth exceeded cap ({MAX_NODE_DEPTH})
Error message
JSON Schema node depth exceeded cap ({MAX_NODE_DEPTH}) What it means
dereference_json_schema refuses to walk schemas whose object nesting exceeds MAX_NODE_DEPTH (512). This cap exists so pathological schemas (cyclic data or billion-laughs-style expansion) raise a clean error instead of exhausting Python's recursion limit.
Source
Thrown at python/composio/utils/json_schema.py:170
root = t.cast(t.Dict[str, t.Any], schema)
# Identity-based cycle guard for the *current* walk path. Python doesn't
# suffer JS-style prototype pollution, so unlike the TS port there's no
# need to filter ``__proto__``/``constructor`` keys while cloning.
visiting: t.Set[int] = set()
# ``walk`` uses explicit loops (not comprehensions) so each level of schema
# nesting costs exactly one Python stack frame. That keeps ``MAX_NODE_DEPTH``
# the binding limit under the interpreter's default recursion ceiling, so a
# pathologically deep schema fails with our typed error rather than a bare
# ``RecursionError`` (which is also caught at the call site as a backstop).
def walk(
node: t.Any,
visited_refs: t.FrozenSet[str],
chain_depth: int,
node_depth: int,
) -> t.Any:
if node_depth >= MAX_NODE_DEPTH:
raise JSONSchemaRefResolutionError(
f"JSON Schema node depth exceeded cap ({MAX_NODE_DEPTH})"
)
if isinstance(node, list):
node_id = id(node)
if node_id in visiting:
return _cycle_break_sentinel()
visiting.add(node_id)
try:
cloned_list: t.List[t.Any] = []
for item in node:
cloned_list.append(
walk(item, visited_refs, chain_depth, node_depth + 1)
)
return cloned_list
finally:
visiting.discard(node_id)
View on GitHub (pinned to 64b1b85502)
Solutions
- Inspect the schema's actual depth and collapse unnecessary nesting
- Convert deeply repeated inline structures into $defs + $ref so the walker dedupes
- Truncate or reject the input schema before calling the SDK if it comes from an untrusted source
- Report it if a legitimate Composio tool schema trips the cap
Defensive patterns
Strategy: validation
Validate before calling
def schema_depth(n):
if isinstance(n, dict): return 1 + max((schema_depth(v) for v in n.values()), default=0)
if isinstance(n, list): return 1 + max((schema_depth(v) for v in n), default=0)
return 0
assert schema_depth(schema) < 512 Try / catch
from composio.exceptions import JSONSchemaRefResolutionError
try:
out = dereference_json_schema(schema)
except JSONSchemaRefResolutionError:
schema = simplify(schema) # collapse inline duplication into $defs/$ref
out = dereference_json_schema(schema) Prevention
- Use $defs + $ref instead of inlining repeated nested structures
- Cap generation depth when building schemas programmatically
When it happens
Trigger: Passing a schema with more than 512 levels of nested properties/items/anyOf containers, or a self-referential structure that expands without $ref cycle protection, to dereference_json_schema or any wrapper (substitute_file_uploads, alias_tool_input_schema).
Common situations: Machine-generated schemas from recursive models (tree types without $ref indirection); malicious or corrupted schema payloads; accidental self-nesting when a schema is built programmatically.
Related errors
- JSON Schema $ref chain exceeded depth cap ({MAX_REF_CHAIN_DE
- Cannot resolve $ref {pointer}
- JSON Schema nesting too deep to dereference
- Invalid property type {p_type}: {schema!r}
- JSON Schema node depth exceeded cap (${MAX_NODE_DEPTH})
AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28).
Data as JSON: /api/errors/3a4089dcd019e2f4.
Report an issue: GitHub.