iOfficeAI/OfficeCLI · error · InvalidOperationException
headless screenshot failed.
Error message
headless screenshot failed.
What it means
The two-pass chrome path succeeded in pass one (DOM dump, MMDREADY, a valid viewBox), but the second pass — HtmlScreenshot.CaptureChromeSized writing the PNG at ceil(w)+2 x ceil(h)+2 — returned false. The screenshot capture itself failed; the diagram was valid but the rasterization step broke.
Source
Thrown at src/officecli/Core/Diagram/MermaidImageRenderer.cs:389
// 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
/// <script src> (a <c>file://</c> for a cached/downloaded copy, else the CDN).</summary>
private static string ResolveMermaidJsRef()
{
try
{
if (File.Exists(CachedJsPath) && new FileInfo(CachedJsPath).Length > 500_000)
return new Uri(CachedJsPath).AbsoluteUri;
Directory.CreateDirectory(CacheDir);
foreach (var url in new[] { MirrorUrl, CdnUrl }) // mirror first, CDN fallback
{
tryView on GitHub (pinned to 1ced45e900)
Solutions
- Check the temp path is writable and has free space.
- Retry once — chrome screenshot failures are often transient.
- For very large diagrams, scale down or use render=native.
- Ensure chrome isn't being killed by a resource limit (ulimit/cgroup memory) during capture.
Defensive patterns
Strategy: retry
Validate before calling
// Confirm the temp path is writable and disk isn't full before the screenshot pass
var tmp = Path.GetTempPath();
if (!HasFreeSpace(tmp)) throw new InvalidOperationException("temp volume full; cannot write screenshot."); Try / catch
for (int attempt = 0; ; attempt++)
{
try { return HtmlScreenshot.CaptureChromeSized(htmlPath, pngPath, w, h)
? pngPath : throw new InvalidOperationException("headless screenshot failed."); }
catch (InvalidOperationException ex) when (ex.Message.Contains("screenshot failed", StringComparison.Ordinal) && attempt < 1)
{ /* chrome flake — retry once */ }
} Prevention
- Keep temp volume with free space and writable.
- Retry once on screenshot failures (often transient chrome flake).
- Avoid extremely large viewports that chrome may reject.
When it happens
Trigger: CaptureChromeSized returns false when the headless screenshot call fails: chrome crashed mid-capture, the output path wasn't writable, the viewport size was rejected, or a chrome timeout during the screenshot pass.
Common situations: Temp directory not writable / out of disk; chrome instability under rapid repeated launches (flaky in CI); extremely large computed viewport (huge diagram) that chrome refuses; antivirus/SELinux blocking the PNG write.
Related errors
- headless browser produced no output.
- mmdc failed (exit {p.ExitCode}). {msg}
- mermaid failed to render: {ExtractMermaidMessage(dom)}
- mermaid produced no diagram (mermaid.js failed to load or th
- failed to start mmdc.
AI-assisted analysis of iOfficeAI/OfficeCLI@1ced45e900 (2026-08-13).
Data as JSON: /api/errors/3154f0903bd354ee.
Report an issue: GitHub.