ComposioHQ/composio · error · Error

Tool schema nesting exceeded the maximum supported depth

Error message

Tool schema nesting exceeded the maximum supported depth (${MAX_SCHEMA_DEPTH})

What it means

The SDK renames tool-schema property keys that collide with dangerous prototypes, and recursively sanitizes the schema with a hard depth cap (MAX_SCHEMA_DEPTH). sanitizeNode throws when the tool's JSON schema nests deeper than that cap, protecting against cyclic or pathological schemas.

Solutions

  1. Inspect the failing tool's schema and flatten or remove unnecessary nesting
  2. If the schema is recursive, express it with $defs/$ref instead of inline expansion so the physical nesting is shallow
  3. Reduce nesting in the tool's parameter type definition before registering the tool
  4. Report the tool/schema to Composio if it's a built-in integration tool you can't modify
Defensive patterns

Strategy: validation

Validate before calling

const schemaDepth = (s: object, d = 0): number =>
  d > 20 ? d : Math.max(d, ...Object.values(s)
    .filter(v => v && typeof v === 'object')
    .map(v => schemaDepth(v as object, d + 1)));
if (schemaDepth(toolSchema) >= MAX_SCHEMA_DEPTH) throw new Error('schema too deep');

Type guard

null

Try / catch

try {
  await composio.tools.execute(action, args);
} catch (e) {
  if (e instanceof Error && e.message.includes('nesting exceeded the maximum supported depth')) {
    // flatten or fix the tool schema
  }
}

Prevention

When it happens

Trigger: Registering or executing a tool whose parameter JSON schema (nested objects/arrays/allOf etc.) exceeds MAX_SCHEMA_DEPTH — often a schema with an accidental self-referencing $ref-like cycle, or a generated schema with extremely deep nesting.

Common situations: Auto-generated OpenAPI/JSON schemas with recursive models expanded inline; deeply nested config types from codegen; a tool definition accidentally embedding itself.

Related errors


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

Appendix: source

Thrown at ts/packages/core/src/utils/schemaPropertyKeys.ts:219

 * Recursively sanitizes the property keys of a JSON-schema node, returning the
 * rewritten node and a {@link KeyMapping} shaped like the node. Traversal covers
 * object `properties`, array `items`/`prefixItems`, the composition keywords
 * (`allOf`/`anyOf`/`oneOf`, `not`/`if`/`then`/`else` — whose renames merge into
 * this level), and the rewrite-only positions in {@link REWRITE_ONLY_SINGLE_KEYWORDS}
 * / {@link REWRITE_ONLY_MAP_KEYWORDS}.
 *
 * The input node is never mutated; a new node is returned.
 */
function sanitizeNode(
  node: Record<string, unknown>,
  policy: KeySanitizationPolicy,
  depth = 0
): {
  node: Record<string, unknown>;
  mapping: KeyMapping;
} {
  if (depth >= MAX_SCHEMA_DEPTH) {
    throw new Error(
      `Tool schema nesting exceeded the maximum supported depth (${MAX_SCHEMA_DEPTH})`
    );
  }

  const result: Record<string, unknown> = { ...node };
  // Lookup/result tables are prototype-free so a property key that collides with
  // an `Object.prototype` member (`__proto__`, `constructor`, `toString`, …)
  // becomes a plain own entry instead of resolving to (or reparenting via) the
  // inherited member. Mirrors the `POLLUTING_KEYS` defense in `jsonSchema.ts`.
  const renames: Record<string, string> = Object.create(null);
  const children: Record<string, KeyMapping> = Object.create(null);
  const mapping: KeyMapping = { renames, children };

  const properties = node.properties;
  if (isPlainObject(properties)) {
    const newProperties: Record<string, unknown> = Object.create(null);
    const renamedOriginalToSanitized: Record<string, string> = Object.create(null);

View on GitHub (pinned to 64b1b85502)