ComposioHQ/composio · error · RangeError

Tool arguments exceed maximum nesting depth of ${MAX_NODE_DE

Error message

Tool arguments exceed maximum nesting depth of ${MAX_NODE_DEPTH}

What it means

omitNulls walks tool arguments against the schema and throws RangeError when the arguments object nests deeper than MAX_NODE_DEPTH — i.e. the runtime input, not the schema, is pathologically deep.

Source

Thrown at ts/packages/core/src/utils/jsonSchema.ts:952

      if (!Array.isArray(branches)) continue;
      for (const branch of branches) {
        const found = find(branch, depth + 1);
        if (found) return found;
      }
    }
    return undefined;
  };
  return find(resolved, 0) ?? resolved;
}

function omitNulls(
  value: unknown,
  schema: unknown,
  root: Record<string, unknown>,
  depth: number
): unknown {
  if (depth > MAX_NODE_DEPTH) {
    throw new RangeError(`Tool arguments exceed maximum nesting depth of ${MAX_NODE_DEPTH}`);
  }
  const node = selectBranchFor(schema, value, root);
  if (Array.isArray(value)) {
    const items = node && isPlainObject(node.items) ? node.items : undefined;
    return value.map(item => omitNulls(item, items, root, depth + 1));
  }
  if (!isPlainObject(value)) return value;

  const properties = node && isPlainObject(node.properties) ? node.properties : {};
  const clone: Record<string, unknown> = {};
  for (const [key, child] of Object.entries(value)) {
    const propertySchema = Object.prototype.hasOwnProperty.call(properties, key)
      ? properties[key]
      : undefined;
    if (child === null) {
      if (propertySchema === undefined || schemaAcceptsNull(propertySchema, root)) {
        setOwn(clone, key, child);
      }

View on GitHub (pinned to 64b1b85502)

Solutions

  1. Validate/limit argument nesting before execute(); reject payloads deeper than a sane bound.
  2. JSON.stringify the arguments first — cyclic structures will throw there and reveal the bug.
  3. Cap LLM output size and nesting when arguments are model-authored.

Example fix

// before
await tool.execute(args);
// after
const depth = (v: unknown, d = 0): number =>
  v && typeof v === 'object'
    ? Math.max(d, ...Object.values(v as object).map(x => depth(x, d + 1)))
    : d;
if (depth(args) > 100) throw new Error('arguments too deeply nested');
await tool.execute(args);
Defensive patterns

Strategy: validation

Validate before calling

const depth = (v: unknown, d = 0): number =>
  v && typeof v === 'object'
    ? Math.max(d, ...Object.values(v as object).map(x => depth(x, d + 1)))
    : d;
if (depth(args) > 100) throw new Error('arguments too deep');

Prevention

When it happens

Trigger: Executing a tool with arguments containing extremely deep nested objects/arrays (e.g. an LLM-generated payload with runaway recursion), or a self-referencing object that escaped JSON serialization bounds.

Common situations: Untrusted or model-generated tool arguments; clients that build arguments recursively; crafted payloads.

Related errors


AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28). Data as JSON: /api/errors/4a38fa6003b312a9. Report an issue: GitHub.