DayuanJiang/next-ai-draw-io · error · Error
Failed to construct <diagram> element for new page
Error message
Failed to construct <diagram> element for new page
What it means
A defensive unreachable-in-practice guard in addPageToDoc: the temp document parsed without a parsererror, but querySelector('diagram') returned null. Because the wrapper snippet is constructed with an explicit <diagram> element, this can only fire if the wrapper itself was corrupted — e.g. id or name attributes containing characters (unescaped quotes) that broke the snippet so the diagram tag wasn't recognized.
Source
Thrown at packages/mcp-server/src/pages.ts:269
throw new Error(
"addPageToDoc: opts.xml must be a bare <mxGraphModel>.",
)
}
inner = trimmed
} else {
inner = `<mxGraphModel><root><mxCell id="0"/><mxCell id="1" parent="0"/></root></mxGraphModel>`
}
const snippet = `<wrapper><diagram id="${escapeAttr(id)}" name="${escapeAttr(name)}">${inner}</diagram></wrapper>`
const tempDoc = new DOMParser().parseFromString(snippet, "text/xml")
if (tempDoc.querySelector("parsererror")) {
throw new Error(
"Failed to parse new page xml — make sure it is a valid <mxGraphModel>",
)
}
const newDiagram = tempDoc.querySelector("diagram")
if (!newDiagram) {
throw new Error("Failed to construct <diagram> element for new page")
}
const imported = doc.importNode(newDiagram, true) as Element
doc.documentElement.appendChild(imported)
return {
id,
name,
index: existing.length,
cellCount: imported.querySelectorAll("mxCell").length,
}
}
/** Rename the page matched by selector. Returns true on success. */
export function renamePageInDoc(
doc: Document,
selector: PageSelector,
newName: string,View on GitHub (pinned to 155ef4f7ac)
Solutions
- Sanitize opts.id/opts.name (strip or escape quotes, '<', '&' ) before calling
- Use a generated safe id and put the fancy name in opts.name with escaping verified
- Report as a library bug if id/name are plain alphanumerics — the guard should be unreachable
- Check listPagesFromDoc afterward instead of relying on this error for flow control
Example fix
// before
addPageToDoc(doc, { id: 'my"page', name: 'My "Quoted" Page' })
// after
const safe = (s: string) => s.replace(/[&<>"]/g, (c) => ({'&':'&','<':'<','>':'>','"':'"'}[c]!))
addPageToDoc(doc, { id: 'mypage', name: safe('My "Quoted" Page') }) Defensive patterns
Strategy: try-catch
Validate before calling
const safeId = opts.id?.replace(/[^\w.-]/g, '_') const safeName = opts.name?.replace(/[&<>"]/g, '') // pass safeId/safeName to addPageToDoc
Type guard
function isSafePageId(id: string): boolean {
return /^[A-Za-z0-9._-]+$/.test(id)
} Try / catch
try { addPageToDoc(doc, { id, name }) } catch (e) { if ((e as Error).message.includes('Failed to construct')) throw new Error(`id/name broke xml construction: ${JSON.stringify({ id, name })}`) else throw e } Prevention
- Sanitize page ids and names before passing them in
- Use generated ids for programmatic pages
- Treat this error as a signal your escaping helper has a gap — file it upstream
When it happens
Trigger: Passing an opts.id or opts.name containing double quotes or '<' that escapeAttr failed to neutralize, producing '<diagram id="a"b" ...>' which parses into unexpected structure rather than a clean parsererror.
Common situations: Page names copied from rich text containing quotes; ids generated from unsanitized user input; edge cases in the escaping helper.
Related errors
- Page id "${id}" already exists
- addPageToDoc: opts.xml must be a bare <mxGraphModel>.
- No SVG element found in the input string.
- SVG element does not have a 'content' attribute.
- No diagram element found
AI-assisted analysis of DayuanJiang/next-ai-draw-io@155ef4f7ac (2026-08-27).
Data as JSON: /api/errors/04f598167442100d.
Report an issue: GitHub.