iOfficeAI/OfficeCLI · error · InvalidOperationException

failed to start mmdc.

Error message

failed to start mmdc.

What it means

Thrown by RenderViaMmdc (MermaidImageRenderer.cs:319) when Process.Start returns null for the located mmdc executable. mmdc is located via the OFFICECLI_MMDC env var (explicit path) or the PATH. If Process.Start cannot launch the resolved path (e.g. it is not a real executable, lacks execute permission, or the platform returns null), this fires. Note RenderToPngFile catches this and cascades to the chrome-family backend, so the user only sees it when both backends fail; the final thrown error is whichever backend's failure was recorded first.

Source

Thrown at src/officecli/Core/Diagram/MermaidImageRenderer.cs:319

                RedirectStandardOutput = true,
                // CONSISTENCY(child-stream-encoding): see BlankDocCreator.
                StandardOutputEncoding = System.Text.Encoding.UTF8,
                StandardErrorEncoding = System.Text.Encoding.UTF8,
                UseShellExecute = false,
                CreateNoWindow = true,
            };
            psi.ArgumentList.Add("-i"); psi.ArgumentList.Add(inPath);
            psi.ArgumentList.Add("-o"); psi.ArgumentList.Add(outPath);
            psi.ArgumentList.Add("-b"); psi.ArgumentList.Add(SafeBackground(background));
            psi.ArgumentList.Add("-s"); psi.ArgumentList.Add("2"); // HiDPI for crisp raster
            var pcfg = Environment.GetEnvironmentVariable("OFFICECLI_MMDC_PUPPETEER");
            if (!string.IsNullOrWhiteSpace(pcfg) && File.Exists(pcfg))
            {
                psi.ArgumentList.Add("-p"); psi.ArgumentList.Add(pcfg);
            }

            using var p = Process.Start(psi)
                ?? throw new InvalidOperationException("failed to start mmdc.");
            // Async-drain both streams: the serial stderr-then-stdout reads
            // interlocked when mmdc filled the stdout pipe first (bounded by
            // the 120s kill below, but a wasted two minutes per diagram).
            var errTask = p.StandardError.ReadToEndAsync();
            var outTask = p.StandardOutput.ReadToEndAsync();
            if (!p.WaitForExit(120_000))
            {
                try { p.Kill(true); } catch { /* best effort */ }
                throw new InvalidOperationException("mmdc timed out after 120s.");
            }
            if (p.ExitCode != 0 || !File.Exists(outPath))
            {
                var msg = $"{errTask.Result}{outTask.Result}".Trim();
                // A parse/unknown-type failure is bad input, not a broken mmdc; class
                // it as syntax so the Add path surfaces it (and does not fall back).
                if (LooksLikeSyntaxError(msg))
                    throw new MermaidSyntaxException(
                        $"mermaid syntax error: {msg} "

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Install mermaid-cli globally (npm install -g @mermaid-js/mermaid-cli) and verify 'mmdc -V' runs.
  2. Set OFFICECLI_MMDC to the absolute path of the actual executable (e.g. /usr/bin/mmdc or the .cmd on Windows), not the package folder.
  3. Ensure the resolved path has execute permission (chmod +x on Linux/macOS).
  4. If mmdc cannot be fixed, ensure a chrome-family browser (Chrome/Chromium/Edge) is installed so the chrome fallback backend succeeds.

Example fix

// before
export OFFICECLI_MMDC=/usr/lib/node_modules/@mermaid-js/mermaid-cli
// after
export OFFICECLI_MMDC=/usr/lib/node_modules/@mermaid-js/mermaid-cli/src/cli.js
# or simply rely on a working PATH install:
npm install -g @mermaid-js/mermaid-cli
unset OFFICECLI_MMDC
Defensive patterns

Strategy: validation

Validate before calling

static void EnsureMmdcAvailable()
{
    var exe = Environment.GetEnvironmentVariable("OFFICECLI_MMDC");
    if (!string.IsNullOrWhiteSpace(exe) && !File.Exists(exe))
        throw new InvalidOperationException($"OFFICECLI_MMDC points to a missing file: {exe}");
    if (string.IsNullOrWhiteSpace(exe) && HtmlScreenshot.Which("mmdc") == null)
        throw new InvalidOperationException("mmdc not found on PATH; install mermaid-cli or set OFFICECLI_MMDC");
}

// call before RenderToPngFile, or gate on MermaidImageRenderer.IsAvailable()

Type guard

// no static type guard; use the availability check:
static bool CanRenderViaMmdcOrChrome() => MermaidImageRenderer.IsAvailable();

Try / catch

try { var png = MermaidImageRenderer.RenderToPngFile(mermaid, bg); }
catch (InvalidOperationException ex) when (ex.Message.Contains("mmdc") || ex.Message.Contains("mermaid-cli"))
{
    // no image backend works — fall back to the native synthesizer
    var graph = DiagramCompiler.Compile(mermaid);
}

Prevention

When it happens

Trigger: OFFICECLI_MMDC points to a file that is not executable or is a script without a shebang/extension the OS can launch; mmdc was found on PATH but is a broken symlink or a non-executable shim; Process.Start returns null on the current platform for the resolved path.

Common situations: Pointing OFFICECLI_MMDC at the npm package directory instead of the bin/mmdc entry; a PATH entry that resolves to a .js source file rather than the installed CLI wrapper; permission bits missing on Linux/macOS after a manual copy.

Related errors


AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13). Data as JSON: /api/errors/23e392ba3ae0aeff. Report an issue: GitHub.