{"record":{"id":"e60b2e2fefd2137f","repo":"iOfficeAI/OfficeCLI","slug":"max-depth-exceeded","errorCode":"max_depth_exceeded","errorMessage":"Document nesting exceeds the maximum supported depth (~{MaxRecursionDepth}); the file may be malformed or crafted to exhaust resources.","messagePattern":"Document nesting exceeds the maximum supported depth \\(~(.+?)\\); the file may be malformed or crafted to exhaust resources\\.","errorType":"error_code","errorClass":"CliException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/DocumentLimits.cs","lineNumber":117,"sourceCode":"    /// renderer has descended too far. Call at the top of each recursive method\n    /// so a maliciously deep document fails with a clean error instead of an\n    /// uncatchable StackOverflowException.\n    ///\n    /// Two complementary guards, because the safe depth depends on thread stack\n    /// size (the 8 MB main thread tolerates far deeper recursion than the ~1 MB\n    /// thread-pool threads the resident/watch server uses, and renderer frames\n    /// are large):\n    ///  - <see cref=\"MaxRecursionDepth\"/> bounds the worst-case time/O(n^2) cost\n    ///    on any stack;\n    ///  - <see cref=\"RuntimeHelpers.TryEnsureSufficientExecutionStack\"/> probes\n    ///    the *actual* remaining stack and trips before a real overflow, so the\n    ///    guard adapts to whatever thread the call runs on (mirrors the probe in\n    ///    <see cref=\"OfficeCli.Core.Formula.FormulaEvaluator\"/>).\n    /// </summary>\n    public static void EnsureDepth(int depth)\n    {\n        if (depth > MaxRecursionDepth || !RuntimeHelpers.TryEnsureSufficientExecutionStack())\n            throw new CliException(\n                $\"Document nesting exceeds the maximum supported depth (~{MaxRecursionDepth}); \" +\n                \"the file may be malformed or crafted to exhaust resources.\")\n            {\n                Code = \"max_depth_exceeded\",\n                Suggestion = \"Verify the document is a genuine Office file.\"\n            };\n    }\n}\n","sourceCodeStart":99,"sourceCodeEnd":126,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/DocumentLimits.cs#L99-L126","documentation":"EnsureDepth guards recursive document parsing against two risks: exceeding MaxRecursionDepth (256) and running out of stack. It throws a CliException (code 'max_depth_exceeded') when either depth > 256 or RuntimeHelpers.TryEnsureSufficientExecutionStack() reports insufficient remaining stack. The probe adapts to the actual thread stack rather than a fixed number, mirroring the FormulaEvaluator guard.","triggerScenarios":"Deeply nested OOXML structures (nested groups, nested tables, recursive containers) push the parser's recursion depth past 256, or the thread's stack is low (resident/watch server thread-pool threads have smaller stacks) so TryEnsureSufficientExecutionStack trips first.","commonSituations":"A malformed or crafted Office file designed as a zip-bomb/stack-exhaustion vector; a genuinely pathological deeply-nested document; running the parser on a thread-pool thread (smaller stack) where 256 isn't even reached before the stack probe trips.","solutions":["Verify the file is a genuine Office document — a crafted file is the most common cause.","If the file is legitimately deep, run parsing on a thread with a larger stack (e.g. a dedicated thread with a bigger stackSize) so the stack probe doesn't trip early.","Catch CliException with Code == 'max_depth_exceeded' and report it as 'unsupported document' rather than crashing the host process.","If authoring the file, flatten excessive nesting."],"exampleFix":"// before — parse on a thread-pool thread (small stack), trips the probe early\nvar doc = Task.Run(() => parser.Parse(stream)).Result;\n\n// after — run on a dedicated thread with a large stack so the 256 depth bound governs\nvar t = new Thread(() => doc = parser.Parse(stream), 0, true, (int)(8 * 1024 * 1024));\nt.Start(); t.Join();","handlingStrategy":"validation","validationCode":"// Before recursing, surface a clean error instead of letting the guard throw deep in the stack\nDocumentLimits.EnsureDepth(currentDepth); // throws CliException(Code=\"max_depth_exceeded\")","typeGuard":null,"tryCatchPattern":"try { parser.Parse(stream); }\ncatch (CliException ex) when (ex.Code == \"max_depth_exceeded\")\n{\n    // report unsupported/crafted document; do not crash the host\n    logger.Warn(\"Document nesting too deep or crafted; rejected. {Suggestion}\", ex.Suggestion);\n}","preventionTips":["Run deep-parse work on a thread with a large stack (e.g. 8MB) so the stack probe isn't the bottleneck.","Catch CliException with Code 'max_depth_exceeded' explicitly and report it.","Treat untrusted Office files as potentially crafted; the guard exists to stop resource exhaustion."],"tags":["recursion","stack","resource-exhaustion","security","document","cli-exception"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}