iOfficeAI/OfficeCLI · error · InvalidOperationException

headless browser produced no output.

Error message

headless browser produced no output.

What it means

The chrome-family renderer writes an HTML file and asks HtmlScreenshot.DumpDom to load it in a headless browser and return the rendered DOM. DumpDom returned null — the browser produced no output at all. This is the earliest failure point in the two-pass chrome path: the DOM dump (used to read the diagram's viewBox and the MMDREADY/MMDSYNTAX/MMDERR title) never came back.

Source

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

    // ----- chrome-family browser (mermaid.js in a page → sized screenshot) --------------

    /// <summary>Two chrome passes: dump the DOM to read the diagram's viewBox, then
    /// screenshot at exactly that size (HiDPI). PNG bakes in the browser's rendering
    /// so mermaid's foreignObject labels — invisible to Office as SVG — appear.</summary>
    private static string RenderViaChrome(string mermaid, string? background)
    {
        // A styled source (theme/layout/look frontmatter) is rendered by the ESM
        // build (the UMD global does not render frontmatter, and elk is ESM-only);
        // a plain source keeps the offline-cached UMD path unchanged.
        var html = SourceNeedsEsm(mermaid)
            ? BuildHtmlEsm(mermaid, SourceNeedsElk(mermaid), SafeBackground(background))
            : BuildHtml(mermaid, ResolveMermaidJsRef(), SafeBackground(background));
        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);

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Verify headless chrome launches: run `chrome --headless --dump-dom file:///tmp/x.html` directly.
  2. If running as root/in a container, ensure the headless launch flags include --no-sandbox (or run as a non-root user).
  3. Confirm chrome is discoverable by the tool's resolver (set the chrome path env var the resolver honors).
  4. Install missing chrome runtime libraries; fall back to render=native if chrome cannot be made to run.

Example fix

// before
var dom = HtmlScreenshot.DumpDom(htmlPath)
    ?? throw new InvalidOperationException("headless browser produced no output.");

// after — distinguish launch failure from empty DOM for a clearer error
var dom = HtmlScreenshot.DumpDom(htmlPath);
if (dom is null)
    throw new InvalidOperationException(
        HtmlScreenshot.ChromeAvailable()
            ? "headless browser produced no output (chrome launched but returned no DOM)."
            : "headless chrome not found or failed to launch; install chrome or use render=native.");
Defensive patterns

Strategy: validation

Validate before calling

// Confirm chrome is launchable before the DOM-dump path
if (!HtmlScreenshot.ChromeAvailable())
    throw new InvalidOperationException("headless chrome not found; install it or use render=native.");

Try / catch

try
{
    dom = HtmlScreenshot.DumpDom(htmlPath)
        ?? throw new InvalidOperationException("headless browser produced no output.");
}
catch (InvalidOperationException ex) when (ex.Message.Contains("no output", StringComparison.Ordinal))
{
    png = MermaidImageRenderer.RenderNative(mermaid, bg);
}

Prevention

When it happens

Trigger: HtmlScreenshot.DumpDom returns null when the headless browser failed to launch or crashed before emitting any DOM — missing chrome binary, chrome killed on launch (sandbox/permissions), a timeout inside DumpDom itself, or the html path being unreadable.

Common situations: Running headless chrome as root without --no-sandbox; chrome not installed or not on the resolver path; a locked-down CI container that blocks process spawning; an OS update removed a chrome dependency library.

Related errors


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