{"record":{"id":"5761e0680cf6d999","repo":"iOfficeAI/OfficeCLI","slug":"unknown-diagram-layout-layout-valid-string","errorCode":null,"errorMessage":"unknown diagram layout '{layout}'. Valid: {string.Join(\", \", Layouts)}.","messagePattern":"unknown diagram layout '(.+?)'\\. Valid: (.+?)\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/officecli/Core/Diagram/MermaidImageRenderer.cs","lineNumber":134,"sourceCode":"    /// <c>--- config: … ---</c> frontmatter block, so they render AND round-trip\n    /// (the composed source is what gets stamped into alt-text). Returns the\n    /// source unchanged when no option is set. Rejects unknown values with a\n    /// message listing the valid ones. When the source already carries its own\n    /// frontmatter or an <c>%%{init}%%</c> directive, the source wins and the\n    /// options are ignored (caller may warn) — merging into an existing block is\n    /// out of scope and would risk producing a malformed document.\n    /// </summary>\n    public static string ComposeSource(string mermaid, string? theme, string? layout, string? look)\n    {\n        theme = string.IsNullOrWhiteSpace(theme) ? null : theme.Trim();\n        layout = string.IsNullOrWhiteSpace(layout) ? null : layout.Trim();\n        look = string.IsNullOrWhiteSpace(look) ? null : look.Trim();\n        if (theme == null && layout == null && look == null) return mermaid;\n\n        if (theme != null && !Themes.Contains(theme))\n            throw new ArgumentException($\"unknown diagram theme '{theme}'. Valid: {string.Join(\", \", Themes)}.\");\n        if (layout != null && !Layouts.Contains(layout))\n            throw new ArgumentException($\"unknown diagram layout '{layout}'. Valid: {string.Join(\", \", Layouts)}.\");\n        if (look != null && !Looks.Contains(look))\n            throw new ArgumentException($\"unknown diagram look '{look}'. Valid: classic, handDrawn.\");\n\n        var lead = mermaid.TrimStart();\n        if (lead.StartsWith(\"---\", StringComparison.Ordinal) || lead.StartsWith(\"%%{\", StringComparison.Ordinal))\n            return mermaid; // source already declares config — do not double-inject\n\n        var sb = new StringBuilder(\"---\\nconfig:\\n\");\n        if (theme != null) sb.Append(\"  theme: \").Append(theme.ToLowerInvariant()).Append('\\n');\n        if (layout != null) sb.Append(\"  layout: \").Append(layout.ToLowerInvariant()).Append('\\n');\n        // look's canonical mermaid spelling is camelCase handDrawn; normalize.\n        if (look != null)\n            sb.Append(\"  look: \")\n              .Append(look.Equals(\"handdrawn\", StringComparison.OrdinalIgnoreCase) ? \"handDrawn\" : \"classic\")\n              .Append('\\n');\n        sb.Append(\"---\\n\").Append(mermaid);\n        return sb.ToString();\n    }","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/iOfficeAI/OfficeCLI/blob/1ced45e900782c5083ed550ddf328ee974e425e7/src/officecli/Core/Diagram/MermaidImageRenderer.cs#L116-L152","documentation":"Thrown by MermaidImageRenderer.ComposeSource (MermaidImageRenderer.cs:134) when a non-null layout value is not in the accepted Layouts set {dagre, elk} (case-insensitive). dagre is mermaid's default layered layout; elk requires the ESM elk loader registered at render time. Unknown layout values are rejected before frontmatter injection.","triggerScenarios":"Setting a diagram layout to 'breadthfirst', 'cose', 'circle', 'grid', 'force', or any value outside {dagre, elk}.","commonSituations":"Confusing mermaid's layouts with Cytoscape/d3 layout names; passing 'tree' or 'hierarchical' which are not mermaid layout ids; expecting a layout that requires a plugin not loaded.","solutions":["Use one of: dagre (default layered) or elk (requires ESM elk loader).","Leave layout unset to use mermaid's default (dagre).","For elk, ensure the render path uses the ESM build (it does automatically when layout=elk)."],"exampleFix":"// before\nlayout=breadthfirst\n// after\nlayout=elk","handlingStrategy":"validation","validationCode":"static readonly HashSet<string> ValidLayouts = new(StringComparer.OrdinalIgnoreCase) { \"dagre\",\"elk\" };\nstatic string ValidateLayout(string layout) => ValidLayouts.Contains(layout ?? \"\") ? layout : throw new ArgumentException($\"unknown layout '{layout}'\");","typeGuard":"static bool IsValidLayout(string layout) => ValidLayouts.Contains(layout ?? \"\");","tryCatchPattern":"try { MermaidImageRenderer.ComposeSource(mermaid, null, layout, null); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"unknown diagram layout\"))\n{ /* default to null (dagre) or pick dagre/elk */ }","preventionTips":["Use mermaid layout ids (dagre, elk), not Cytoscape names (cose, breadthfirst).","Leave layout null for mermaid's default (dagre).","For elk, the render path automatically uses the ESM elk loader."],"tags":["diagram","mermaid","layout","validation"],"backgroundTag":null,"analyzedSha":"1ced45e900782c5083ed550ddf328ee974e425e7","analyzedAt":"2026-08-13T13:01:07.193Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}