iOfficeAI/OfficeCLI · warning · MermaidSyntaxException

mermaid syntax error: {ExtractMermaidMessage(dom)} (fix the

Error message

mermaid syntax error: {ExtractMermaidMessage(dom)}
(fix the mermaid source, or use render=native for the built-in subset).

What it means

The chrome DOM dump contained <title>MMDSYNTAX</title>, the authoritative signal that mermaid.parse() rejected the source. Because mermaid still injects its red 'Syntax error' bomb graphic into the DOM on failure, the code keys off the title rather than the presence of an <svg>. ExtractMermaidMessage pulls mermaid's captured error text. This is bad input, surfaced as MermaidSyntaxException.

Source

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

        // 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);
            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;
        }

View on GitHub (pinned to 1ced45e900)

Solutions

  1. Read the extracted mermaid message — it names the parse failure and usually the line.
  2. Correct the cited syntax, or simplify to a supported diagram type.
  3. If valid for newer mermaid, update the cached/downloaded mermaid.js (clear the cache so ResolveMermaidJsRef fetches a newer build).
  4. Use render=native if the diagram is within the built-in subset.

Example fix

// before — unsupported syntax in bundled mermaid.js
sequenceDiagram
  Alice>>Bob: hi   // '>>' is not a valid arrow

// after
sequenceDiagram
  Alice->>Bob: hi
Defensive patterns

Strategy: validation

Validate before calling

// Reuse the renderer's own syntax signature set for a cheap pre-check
static bool MayBeSyntaxBroken(string src)
    => src.Contains(" >> ") == false /* example guard for arrow typos */;
// Best: call mermaid.parse() in-page and read the title before committing to a screenshot.

Try / catch

try { png = MermaidImageRenderer.RenderViaChrome(mermaid, bg); }
catch (MermaidSyntaxException ex)
{
    // bad input — report, do not fall back
    result.AddError("mermaid", ex.Message);
}

Prevention

When it happens

Trigger: The HTML harness calls mermaid.parse() on the source; it rejects (throws) and the page sets document.title to MMDSYNTAX with the error text. Happens for malformed mermaid: unknown diagram type, bad directive, unmatched brackets, reserved-word collisions.

Common situations: Source uses syntax or a diagram type unsupported by the bundled mermaid.js version; copy-paste damage; a node id colliding with a mermaid reserved word; frontmatter YAML typo.

Related errors


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