{"record":{"id":"fa132eb81f3b6989","repo":"iOfficeAI/OfficeCLI","slug":"mermaid-syntax-error-extractmermaidmessage-dom","errorCode":null,"errorMessage":"mermaid syntax error: {ExtractMermaidMessage(dom)}\n(fix the mermaid source, or use render=native for the built-in subset).","messagePattern":"mermaid syntax error: (.+?)\n\\(fix the mermaid source, or use render=native for the built-in subset\\)\\.","errorType":"validation","errorClass":"MermaidSyntaxException","httpStatus":null,"severity":"warning","filePath":"src/officecli/Core/Diagram/MermaidImageRenderer.cs","lineNumber":373,"sourceCode":"        // a plain source keeps the offline-cached UMD path unchanged.\n        var html = SourceNeedsEsm(mermaid)\n            ? BuildHtmlEsm(mermaid, SourceNeedsElk(mermaid), SafeBackground(background))\n            : BuildHtml(mermaid, ResolveMermaidJsRef(), SafeBackground(background));\n        var htmlPath = Path.Combine(Path.GetTempPath(), $\"ocli_mmd_{Guid.NewGuid():N}.html\");\n        File.WriteAllText(htmlPath, html);\n        try\n        {\n            var dom = HtmlScreenshot.DumpDom(htmlPath)\n                ?? throw new InvalidOperationException(\"headless browser produced no output.\");\n\n            // The <title> is the AUTHORITATIVE outcome — not the presence of an <svg>.\n            // On a syntax error mermaid.parse() rejects (we capture the message) but\n            // STILL injects its red \"Syntax error\" bomb graphic into the DOM anyway\n            // (suppressErrorRendering doesn't stop it). So a viewBox is present even on\n            // failure; keying off the svg would screenshot the bomb and \"succeed\".\n            // Trust the title: MMDREADY = real render, MMDSYNTAX = bad input, else infra.\n            if (dom.Contains(\"<title>MMDSYNTAX</title>\", StringComparison.Ordinal))\n                throw new MermaidSyntaxException(\n                    \"mermaid syntax error: \" + ExtractMermaidMessage(dom)\n                    + \"\\n(fix the mermaid source, or use render=native for the built-in subset).\");\n            if (!dom.Contains(\"<title>MMDREADY</title>\", StringComparison.Ordinal))\n                throw new InvalidOperationException(\n                    dom.Contains(\"<title>MMDERR</title>\", StringComparison.Ordinal)\n                    ? \"mermaid failed to render: \" + ExtractMermaidMessage(dom)\n                    : \"mermaid produced no diagram (mermaid.js failed to load or the render timed out).\");\n\n            var (w, h) = ParseSvgSize(dom);\n            if (w <= 0 || h <= 0)\n                throw new InvalidOperationException(\"mermaid rendered but produced no measurable svg viewBox.\");\n\n            var pngPath = Path.ChangeExtension(htmlPath, \".png\");\n            if (!HtmlScreenshot.CaptureChromeSized(htmlPath, pngPath,\n                    (int)Math.Ceiling(w) + 2, (int)Math.Ceiling(h) + 2))\n                throw new InvalidOperationException(\"headless screenshot failed.\");\n            return pngPath;\n        }","sourceCodeStart":355,"sourceCodeEnd":391,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/Diagram/MermaidImageRenderer.cs#L355-L391","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the extracted mermaid message — it names the parse failure and usually the line.","Correct the cited syntax, or simplify to a supported diagram type.","If valid for newer mermaid, update the cached/downloaded mermaid.js (clear the cache so ResolveMermaidJsRef fetches a newer build).","Use render=native if the diagram is within the built-in subset."],"exampleFix":"// before — unsupported syntax in bundled mermaid.js\nsequenceDiagram\n  Alice>>Bob: hi   // '>>' is not a valid arrow\n\n// after\nsequenceDiagram\n  Alice->>Bob: hi","handlingStrategy":"validation","validationCode":"// Reuse the renderer's own syntax signature set for a cheap pre-check\nstatic bool MayBeSyntaxBroken(string src)\n    => src.Contains(\" >> \") == false /* example guard for arrow typos */;\n// Best: call mermaid.parse() in-page and read the title before committing to a screenshot.","typeGuard":null,"tryCatchPattern":"try { png = MermaidImageRenderer.RenderViaChrome(mermaid, bg); }\ncatch (MermaidSyntaxException ex)\n{\n    // bad input — report, do not fall back\n    result.AddError(\"mermaid\", ex.Message);\n}","preventionTips":["Test mermaid snippets with the same mermaid.js version before batch use.","Treat MermaidSyntaxException as user input, not infrastructure.","Keep the cached mermaid.js current with the syntax you rely on."],"tags":["mermaid","syntax","validation","user-input","chrome"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}