iOfficeAI/OfficeCLI · error · InvalidOperationException

mermaid produced no diagram (mermaid.js failed to load or th

Error message

mermaid produced no diagram (mermaid.js failed to load or the render timed out).

What it means

The DOM title was none of MMDREADY, MMDSYNTAX, or MMDSYNTAX's render sibling — it lacked MMDREADY entirely and was not MMDSYNTAX or MMDSYNTAX->ERR. With no recognized outcome marker, the failure is classified as infra: mermaid.js never finished, either because the script failed to load or the render timed out before the page could set the title.

Source

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

        var htmlPath = Path.Combine(Path.GetTempPath(), $"ocli_mmd_{Guid.NewGuid():N}.html");
        File.WriteAllText(htmlPath, html);
        try
        {
            var dom = HtmlScreenshot.DumpDom(htmlPath)
                ?? throw new InvalidOperationException("headless browser produced no output.");

            // The <title> is the AUTHORITATIVE outcome — not the presence of an <svg>.
            // On a syntax error mermaid.parse() rejects (we capture the message) but
            // STILL injects its red "Syntax error" bomb graphic into the DOM anyway
            // (suppressErrorRendering doesn't stop it). So a viewBox is present even on
            // failure; keying off the svg would screenshot the bomb and "succeed".
            // Trust the title: MMDREADY = real render, MMDSYNTAX = bad input, else infra.
            if (dom.Contains("<title>MMDSYNTAX</title>", StringComparison.Ordinal))
                throw new MermaidSyntaxException(
                    "mermaid syntax error: " + ExtractMermaidMessage(dom)
                    + "\n(fix the mermaid source, or use render=native for the built-in subset).");
            if (!dom.Contains("<title>MMDREADY</title>", StringComparison.Ordinal))
                throw new InvalidOperationException(
                    dom.Contains("<title>MMDERR</title>", StringComparison.Ordinal)
                    ? "mermaid failed to render: " + ExtractMermaidMessage(dom)
                    : "mermaid produced no diagram (mermaid.js failed to load or the render timed out).");

            var (w, h) = ParseSvgSize(dom);
            if (w <= 0 || h <= 0)
                throw new InvalidOperationException("mermaid rendered but produced no measurable svg viewBox.");

            var pngPath = Path.ChangeExtension(htmlPath, ".png");
            if (!HtmlScreenshot.CaptureChromeSized(htmlPath, pngPath,
                    (int)Math.Ceiling(w) + 2, (int)Math.Ceiling(h) + 2))
                throw new InvalidOperationException("headless screenshot failed.");
            return pngPath;
        }
        finally { try { File.Delete(htmlPath); } catch { /* best effort */ } }
    }

    /// <summary>Cache → one-time download → live CDN. Returns a URL usable as a

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Pre-cache mermaid.js so ResolveMermaidJsRef doesn't depend on the network (place a >500KB copy at CachedJsPath).
  2. Check network/proxy access to the CDN; allowlist the mermaid CDN host.
  3. Retry once — a transient CDN failure is the most common cause.
  4. Use render=native to avoid the browser/CDN path entirely.

Example fix

// before — relies on CDN at runtime, fails offline
var png = MermaidImageRenderer.RenderViaChrome(mermaid, bg);

// after — seed the cache once so the browser path is offline-safe
if (!File.Exists(CachedJsPath) || new FileInfo(CachedJsPath).Length <= 500_000)
    File.WriteAllBytes(CachedJsPath, DownloadMermaidJs());
var png = MermaidImageRenderer.RenderViaChrome(mermaid, bg);
Defensive patterns

Strategy: retry

Validate before calling

// Ensure an offline-safe mermaid.js cache before relying on the browser path
if (!File.Exists(CachedJsPath) || new FileInfo(CachedJsPath).Length <= 500_000)
    File.WriteAllBytes(CachedJsPath, DownloadMermaidJsWithTimeout());

Try / catch

for (int attempt = 0; attempt < 2; attempt++)
{
    try { return MermaidImageRenderer.RenderViaChrome(mermaid, bg); }
    catch (InvalidOperationException ex) when (ex.Message.Contains("failed to load or the render timed out", StringComparison.Ordinal) && attempt == 0)
    { /* transient CDN — retry once */ }
}
return MermaidImageRenderer.RenderNative(mermaid, bg);

Prevention

When it happens

Trigger: ResolveMermaidJsRef fell through cache → download → live CDN and the CDN was unreachable (offline, proxy block, 404), so mermaid never defined and the title was never set; or the page's render timed out inside DumpDom's wait window before mermaid finished.

Common situations: Air-gapped/offline machine with no cached mermaid.js and CDN unreachable; corporate proxy blocking the CDN; a transient network drop during the one-time download; the render genuinely exceeding DumpDom's internal wait.

Understand the failure class

Related errors


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