ComposioHQ/composio · error · ValueError
Tool arguments exceed maximum nesting depth of {MAX_NODE_DEP
Error message
Tool arguments exceed maximum nesting depth of {MAX_NODE_DEPTH} What it means
omit_null_tool_arguments walks the argument payload against the schema to drop null-valued optional fields, and _omit_nulls enforces MAX_NODE_DEPTH on the combined value/schema recursion. Deeply nested arguments (or a schema that makes the walker chase many branches) exceed the cap and raise ValueError.
Source
Thrown at python/composio/utils/strict_schema.py:436
return candidate
for keyword in ("anyOf", "oneOf"):
branches = candidate.get(keyword)
if not isinstance(branches, list):
continue
for branch in branches:
found = find(branch, depth + 1)
if found is not None:
return found
return None
return find(resolved, 0) or resolved
def _omit_nulls(
value: t.Any, schema: t.Any, root: dict[str, t.Any], depth: int
) -> t.Any:
if depth > MAX_NODE_DEPTH:
raise ValueError(
f"Tool arguments exceed maximum nesting depth of {MAX_NODE_DEPTH}"
)
node = _select_branch_for(schema, value, root) or {}
if isinstance(value, list):
items = node.get("items") if isinstance(node.get("items"), dict) else None
return [_omit_nulls(item, items, root, depth + 1) for item in value]
if not isinstance(value, dict):
return value
declared = node.get("properties")
properties: dict[str, t.Any] = declared if isinstance(declared, dict) else {}
clone: dict[str, t.Any] = {}
for key, child in value.items():
property_schema = properties.get(key)
if child is None:
if property_schema is None or _schema_accepts_null(property_schema, root):
clone[key] = child
continue
clone[key] = _omit_nulls(child, property_schema, root, depth + 1)View on GitHub (pinned to 64b1b85502)
Solutions
- Flatten arguments before the call: send big/deep blobs as a single string field or file reference rather than structured arguments
- Pre-check depth with a quick recursive counter and split/truncate the payload
- Simplify the tool's input schema so anyOf/branch selection doesn't compound depth
- If the payload is legitimately huge, use file upload paths instead of inline arguments
Example fix
# before
args = json.loads(deep_document_text) # possibly 50+ levels
tool.run(args)
# after
args = {"document": deep_document_text}
tool.run(args) Defensive patterns
Strategy: validation
Validate before calling
def payload_depth(v, d=0):
if isinstance(v, dict): return max([payload_depth(x, d+1) for x in v.values()], default=d)
if isinstance(v, list): return max([payload_depth(x, d+1) for x in v], default=d)
return d
if payload_depth(args) > 50: args = {"blob": json.dumps(args)} Try / catch
try:
tool.run(args)
except ValueError as e:
if "nesting depth" in str(e):
tool.run({"document": json.dumps(args)}) Prevention
- Send large/deep payloads as strings or file references, not structured args
- Flatten argument structures in your own layer
- Cap LLM output nesting via prompt constraints
When it happens
Trigger: Calling a tool (or explicitly omit_null_tool_arguments) with arguments nested deeper than the limit — e.g. deeply nested JSON payloads from file parsing, or list-of-list structures combined with anyOf-heavy schemas that multiply traversal depth.
Common situations: Uploading parsed JSON documents (ASTs, configs, serialized trees) as tool arguments; LLMs generating extremely nested output; payloads that grew from data-driven nesting without a flattening step.
Related errors
- {error.message}
- Unrecognized key(s) in object: {', '.join(repr(key) for key
- Tool arguments were provided as a string that is not valid J
- Tool arguments must resolve to an object, received {type(val
- JSON Schema exceeds maximum nesting depth of {MAX_NODE_DEPTH
AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28).
Data as JSON: /api/errors/5c4963488186970d.
Report an issue: GitHub.