DayuanJiang/next-ai-draw-io · error · Error
addPageToDoc: opts.xml must be a bare <mxGraphModel>.
Error message
addPageToDoc: opts.xml must be a bare <mxGraphModel>.
What it means
After addPageToDoc builds a wrapper snippet ('<wrapper><diagram id=... name=...>MODEL</diagram></wrapper>') from user-supplied opts.xml and parses it, the parser reported an error node. This means the assembled XML is malformed — almost always because opts.xml (the mxGraphModel) contains invalid XML such as unescaped entities, mismatched tags, or stray characters.
Source
Thrown at packages/mcp-server/src/pages.ts:263
if (isMxFile(trimmed)) {
throw new Error(
"addPageToDoc: opts.xml must be a bare <mxGraphModel>; received a full <mxfile>. Extract the target diagram's <mxGraphModel> first.",
)
}
if (!isMxGraphModel(trimmed)) {
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,
}
}View on GitHub (pinned to 155ef4f7ac)
Solutions
- Escape dynamic text with escapeAttr/escapeXml-equivalents before embedding in XML
- Validate opts.xml parses standalone before calling addPageToDoc
- Replace HTML-only entities ( ) with numeric XML equivalents ( ) or wrap labels as ...escaped HTML per mxGraph conventions
- If concatenating, use DOM APIs (createElement/setTextContent) instead of strings
Example fix
// before
addPageToDoc(doc, { xml: `<mxGraphModel><root><mxCell value="A & B" .../></root></mxGraphModel>` })
// after
const value = 'A & B'
addPageToDoc(doc, { xml: `<mxGraphModel><root><mxCell value="${value}" .../></root></mxGraphModel>` }) Defensive patterns
Strategy: validation
Validate before calling
const probe = new DOMParser().parseFromString(opts.xml, 'text/xml')
if (probe.querySelector('parsererror')) {
throw new Error('opts.xml is not well-formed XML; escape entities/quotes first')
} Type guard
function isWellFormedXml(s: string): boolean {
return !new DOMParser().parseFromString(s, 'text/xml').querySelector('parsererror')
} Try / catch
try { addPageToDoc(doc, { xml }) } catch (e) { if ((e as Error).message.includes('Failed to parse')) throw new Error(`page xml invalid near: ${xml.slice(0, 120)}`) else throw e } Prevention
- Escape user text (&, <, >, ", ') before embedding in xml strings
- Build markup with DOM APIs instead of string concatenation
- Pre-parse opts.xml to fail fast with better context
When it happens
Trigger: Passing opts.xml containing raw '&' or '<' in attributes/values (e.g. a label 'A & B'), truncated markup, or HTML-style entities like that strict XML parsing rejects.
Common situations: Building mxGraphModel strings by concatenation without escaping user text; embedding HTML in cell labels unescaped; copy-pasting from rendered HTML where entities were already decoded.
Related errors
- No diagram element found
- No SVG element found in the input string.
- No encoded data found in the diagram element
- Failed to construct <diagram> element for new page
- Error replacing nodes: ${error}
AI-assisted analysis of DayuanJiang/next-ai-draw-io@155ef4f7ac (2026-08-27).
Data as JSON: /api/errors/dfec7cca748dc43f.
Report an issue: GitHub.