garrytan/gstack · error
invalid mermaid render id: ${id}
Error message
invalid mermaid render id: ${id} What it means
Thrown by __renderMermaid() when the caller-supplied diagram id fails the regex ^[A-Za-z][\w-]*$. Mermaid bakes the id into internal SVG element ids (gradients, markers, clip paths), so an invalid id would produce malformed SVG or id collisions between two diagrams inlined into one document. The guard enforces: starts with a letter, remaining chars are word characters or hyphens. This is a hard precondition before mermaid.render is ever called.
Source
Thrown at lib/diagram-render/src/entry.ts:67
// Font stacks must match make-pdf/src/print-css.ts (sans + CJK + emoji) so
// mermaid's text measurement in this tab matches the print document's layout.
const PRINT_SANS =
'Helvetica, "Liberation Sans", Arial, "Hiragino Kaku Gothic ProN", ' +
'"Noto Sans CJK JP", "Microsoft YaHei", "Apple Color Emoji", ' +
'"Segoe UI Emoji", "Noto Color Emoji", sans-serif';
mermaid.initialize({
startOnLoad: false,
securityLevel: "strict",
theme: "neutral",
fontFamily: PRINT_SANS,
htmlLabels: false,
flowchart: { htmlLabels: false },
});
window.__renderMermaid = async (id: string, text: string): Promise<string> => {
if (!/^[A-Za-z][\w-]*$/.test(id)) throw new Error(`invalid mermaid render id: ${id}`);
const { svg } = await mermaid.render(id, text);
return svg;
};
window.__mermaidToExcalidraw = async (text: string): Promise<string> => {
const { elements, files } = await parseMermaidToExcalidraw(text);
const converted = convertToExcalidrawElements(elements);
const scene = {
type: "excalidraw",
version: 2,
source: "gstack-diagram-render",
elements: converted,
appState: { viewBackgroundColor: "#ffffff" },
files: files ?? {},
};
return JSON.stringify(scene);
};
View on GitHub (pinned to 94993f7401)
Solutions
- Prefix the id with a letter, e.g. 'mermaid-fence-' + index.
- Strip or replace any non-[A-Za-z0-9_-] characters before calling.
- Ensure the id is non-empty and starts with [A-Za-z].
- If auto-generating, use a fixed prefix like 'd' + counter.
Example fix
// before
__renderMermaid('1-flow', graph);
// after
__renderMermaid('mermaid-fence-1', graph); Defensive patterns
Strategy: validation
Validate before calling
function sanitizeMermaidId(id: string): string {
let cleaned = id.replace(/[^\w-]/g, '');
if (!/^[A-Za-z]/.test(cleaned)) cleaned = 'd' + cleaned;
return cleaned || 'diagram';
} Type guard
function isValidMermaidId(id: string): boolean {
return typeof id === 'string' && /^[A-Za-z][\w-]*$/.test(id);
} Prevention
- Generate ids from a fixed prefix + counter: 'mermaid-fence-' + n.
- Strip user-supplied diagram names of non-word characters before use.
- Unit-test the id generator against the regex.
- Document the id contract for any caller of __renderMermaid.
When it happens
Trigger: Caller invokes window.__renderMermaid(id, text) with an id that starts with a digit, contains spaces/slashes/colons, is empty, or includes unicode. Typical orchestrator ids are 'mermaid-fence-<n>' which always pass.
Common situations: Orchestrator bug generating ids from raw fence indices without a letter prefix; user-supplied diagram name used directly as id; id derived from a file path containing slashes; an id that worked in an older mermaid but now fails stricter validation.
Related errors
- excalidraw scene has no elements array
- targetWidthPx out of range: ${px}
- Skill name is empty.
- Invalid skill name "${name}". Must be lowercase letters/digi
- stageSkill: files map is empty.
AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12).
Data as JSON: /api/errors/a19fa00a37aaf526.
Report an issue: GitHub.