{"record":{"id":"5f7a129ef83bd735","repo":"iOfficeAI/OfficeCLI","slug":"mmdc-failed-exit-p-exitcode-msg","errorCode":null,"errorMessage":"mmdc failed (exit {p.ExitCode}). {msg}","messagePattern":"mmdc failed \\(exit (.+?)\\)\\. (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/Diagram/MermaidImageRenderer.cs","lineNumber":339,"sourceCode":"            // interlocked when mmdc filled the stdout pipe first (bounded by\n            // the 120s kill below, but a wasted two minutes per diagram).\n            var errTask = p.StandardError.ReadToEndAsync();\n            var outTask = p.StandardOutput.ReadToEndAsync();\n            if (!p.WaitForExit(120_000))\n            {\n                try { p.Kill(true); } catch { /* best effort */ }\n                throw new InvalidOperationException(\"mmdc timed out after 120s.\");\n            }\n            if (p.ExitCode != 0 || !File.Exists(outPath))\n            {\n                var msg = $\"{errTask.Result}{outTask.Result}\".Trim();\n                // A parse/unknown-type failure is bad input, not a broken mmdc; class\n                // it as syntax so the Add path surfaces it (and does not fall back).\n                if (LooksLikeSyntaxError(msg))\n                    throw new MermaidSyntaxException(\n                        $\"mermaid syntax error: {msg} \"\n                        + \"(fix the mermaid source, or use render=native for the built-in subset).\");\n                throw new InvalidOperationException($\"mmdc failed (exit {p.ExitCode}). {msg}\".Trim());\n            }\n            return outPath;\n        }\n        finally { try { File.Delete(inPath); } catch { /* best effort */ } }\n    }\n\n    // ----- chrome-family browser (mermaid.js in a page → sized screenshot) --------------\n\n    /// <summary>Two chrome passes: dump the DOM to read the diagram's viewBox, then\n    /// screenshot at exactly that size (HiDPI). PNG bakes in the browser's rendering\n    /// so mermaid's foreignObject labels — invisible to Office as SVG — appear.</summary>\n    private static string RenderViaChrome(string mermaid, string? background)\n    {\n        // A styled source (theme/layout/look frontmatter) is rendered by the ESM\n        // build (the UMD global does not render frontmatter, and elk is ESM-only);\n        // a plain source keeps the offline-cached UMD path unchanged.\n        var html = SourceNeedsEsm(mermaid)\n            ? BuildHtmlEsm(mermaid, SourceNeedsElk(mermaid), SafeBackground(background))","sourceCodeStart":321,"sourceCodeEnd":357,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/Diagram/MermaidImageRenderer.cs#L321-L357","documentation":"mmdc exited non-zero (or wrote no output file) but the captured stderr+stdout did NOT match any syntax-error signature, so the failure is classified as infrastructure rather than bad input. The exit code and raw mmdc output are embedded in the message. Unlike a syntax error, this does not fall back silently — it is a hard failure.","triggerScenarios":"mmdc crashes or refuses to run for a non-syntax reason: puppeteer/chrome binary missing or misconfigured, a port conflict, an out-of-memory kill of chrome, an incompatible node version, a broken global mmdc install, or mmdc writing its PNG to an unexpected path so File.Exists(outPath) is false.","commonSituations":"Puppeteer's bundled chromium not installed (`npx puppeteer install`); running on a stripped-down container missing chrome runtime libs; node version mismatch with @mermaid-js/mermaid-cli; OUT_OF_MEMORY in CI killing chrome; mmdc global install corrupted.","solutions":["Run the exact mmdc command shown in the message manually to see the real chrome/puppeteer error.","Ensure puppeteer's chromium is installed and chrome runtime libraries are present (`npx puppeteer browsers install chrome`).","Point OFFICECLI_MMDC at a known-good mmdc and check `mmdc --version` / node version compatibility.","If chrome cannot be made to work in the environment, use render=native to avoid the external process.","Free memory/CPU on the host if chrome is being OOM-killed."],"exampleFix":"// before\nvar png = MermaidImageRenderer.Render(mermaid, bg);\n\n// after — probe mmdc health first, surface a clear error, optional native fallback\nif (string.IsNullOrEmpty(MermaidImageRenderer.ProbeMmdc()))\n    throw new InvalidOperationException(\"mmdc not found; install @mermaid-js/mermaid-cli or set OFFICECLI_MMDC.\");\ntry { var png = MermaidImageRenderer.Render(mermaid, bg); }\ncatch (InvalidOperationException ex) when (ex.Message.StartsWith(\"mmdc failed\")) {\n    // chrome/puppeteer broken in this env — fall back to the built-in native subset\n    var png = MermaidImageRenderer.RenderNative(mermaid, bg);\n}","handlingStrategy":"try-catch","validationCode":"// Probe mmdc health on a trivial diagram once at startup\nstatic bool MmdcHealthy(string mmdc)\n{\n    try\n    {\n        var psi = new ProcessStartInfo(mmdc, \"-i <trivial.mmd> -o /tmp/probe.png\");\n        using var p = Process.Start(psi);\n        return p != null && p.WaitForExit(30_000) && p.ExitCode == 0;\n    }\n    catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try { png = MermaidImageRenderer.Render(mermaid, bg); }\ncatch (InvalidOperationException ex) when (ex.Message.StartsWith(\"mmdc failed\", StringComparison.Ordinal))\n{\n    // infra failure (chrome/puppeteer) — fall back to native subset or report\n    png = MermaidImageRenderer.RenderNative(mermaid, bg);\n}","preventionTips":["Ensure puppeteer's chromium and chrome runtime libs are installed in every environment.","Pin a known-good @mermaid-js/mermaid-cli version.","Prefer render=native in minimal/CI containers where chrome is fragile."],"tags":["mermaid","mmdc","puppeteer","chrome","infrastructure","process"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}