{"record":{"id":"c6b73ece9db5b512","repo":"ComposioHQ/composio","slug":"json-schema-exceeds-maximum-nesting-depth-of-max-c6b73e","errorCode":null,"errorMessage":"JSON Schema exceeds maximum nesting depth of ${MAX_NODE_DEPTH}","messagePattern":"JSON Schema exceeds maximum nesting depth of (.+?)","errorType":"exception","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"ts/packages/core/src/utils/jsonSchema.ts","lineNumber":304,"sourceCode":"}\n\n/**\n * Returns a deep-cloned JSON Schema in which every node that carries a\n * `properties` keyword also carries `type: \"object\"` when it has no explicit\n * `type`. OpenAI tolerates the omission, but Google Gemini enforces OpenAPI\n * 3.0 strictly and rejects function declarations whose nested objects are\n * missing the `type` (see https://github.com/ComposioHQ/composio/issues/4022).\n *\n * The function follows JSON Schema's schema-bearing keywords while keeping\n * property maps and instance values as containers. Nodes that already declare\n * a `type` are left untouched.\n */\nexport function ensureObjectTypeOnProperties<T = unknown>(schema: T): T {\n  type WalkMode = 'schema' | 'schema-array' | 'schema-map' | 'dependencies-map' | 'value';\n\n  function walk(value: unknown, mode: WalkMode, depth = 0): unknown {\n    if (depth > MAX_NODE_DEPTH) {\n      throw new RangeError(`JSON Schema exceeds maximum nesting depth of ${MAX_NODE_DEPTH}`);\n    }\n\n    if (Array.isArray(value)) {\n      const itemMode = mode === 'schema-array' ? 'schema' : 'value';\n      return value.map(item => walk(item, itemMode, depth + 1));\n    }\n\n    if (!isPlainObject(value)) return value;\n\n    const clone: Record<string, unknown> = {};\n    for (const [key, child] of Object.entries(value)) {\n      let childMode: WalkMode = 'value';\n      if (mode === 'schema-map') {\n        childMode = 'schema';\n      } else if (mode === 'dependencies-map') {\n        childMode = Array.isArray(child) ? 'value' : 'schema';\n      } else if (mode === 'schema') {\n        if (SCHEMA_MAP_KEYWORDS.has(key)) {","sourceCodeStart":286,"sourceCodeEnd":322,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/ts/packages/core/src/utils/jsonSchema.ts#L286-L322","documentation":"ensureObjectTypeOnProperties walks the schema to normalize properties and throws RangeError when nesting depth exceeds MAX_NODE_DEPTH, protecting against stack overflow on pathological inputs.","triggerScenarios":"A schema with deeply nested arrays/maps/objects passed through tool parameter normalization (e.g. nested schema-array or dependencies-map modes) deeper than the cap.","commonSituations":"Recursive or machine-generated schemas; user-supplied tool definitions with unbounded self-referencing structures that escaped cycle detection.","solutions":["Reduce schema nesting; collapse unnecessary intermediate levels.","If the schema is user-supplied, validate its depth before registering the tool.","Report tool definitions that legitimately need extreme depth to the SDK maintainers."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const depth = (v: unknown, d = 0): number =>\n  v && typeof v === 'object' ? Math.max(d, ...Object.values(v).map(x => depth(x, d + 1))) : d;\nif (depth(schema) > 100) throw new Error('schema too deep');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Flatten generated schemas.","Treat depth-cap RangeErrors as schema-authoring bugs to fix upstream."],"tags":["json-schema","depth-limit","typescript"],"backgroundTag":"schema-depth-limit-exceeded","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}