DayuanJiang/next-ai-draw-io · error · Error
addPageToDoc: opts.xml must be a bare <mxGraphModel>; receiv
Error message
addPageToDoc: opts.xml must be a bare <mxGraphModel>; received a full <mxfile>. Extract the target diagram's <mxGraphModel> first.
What it means
addPageToDoc requires opts.xml to be a single bare <mxGraphModel> element — the body of one page — because it wraps that markup inside a new <diagram> element. Passing a full multi-page <mxfile> would nest files illegally. This guard (isMxFile) fires before the generic shape check at line 251, which throws the same message for the same condition.
Source
Thrown at packages/mcp-server/src/pages.ts:246
* Returns the new PageInfo. Throws if the requested id collides or the xml
* shape is wrong.
*/
export function addPageToDoc(
doc: Document,
opts: { id?: string; name?: string; xml?: string } = {},
): PageInfo {
const existing = listPagesFromDoc(doc)
const id = opts.id || generatePageId()
if (existing.some((p) => p.id === id)) {
throw new Error(`Page id "${id}" already exists`)
}
const name = opts.name || `Page-${existing.length + 1}`
let inner: string
if (opts.xml?.trim()) {
const trimmed = stripXmlDeclaration(opts.xml.trim())
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>",View on GitHub (pinned to 155ef4f7ac)
Solutions
- Extract the target page's <mxGraphModel> first (see fix below) and pass that as opts.xml
- Or use an API designed for whole-file imports if one exists instead of addPageToDoc
- If you only need an empty page, omit opts.xml entirely
Example fix
// before
addPageToDoc(doc, { xml: fs.readFileSync('other.drawio', 'utf8') })
// after
const src = new DOMParser().parseFromString(fs.readFileSync('other.drawio', 'utf8'), 'text/xml')
const model = src.querySelector('mxfile > diagram > mxGraphModel')
addPageToDoc(doc, { xml: new XMLSerializer().serializeToString(model) }) Defensive patterns
Strategy: type-guard
Validate before calling
function extractFirstMxGraphModel(mxFileXml: string): string | null {
const doc = new DOMParser().parseFromString(mxFileXml, 'text/xml')
const m = doc.querySelector('mxfile > diagram > mxGraphModel') ?? doc.querySelector('mxGraphModel')
return m ? new XMLSerializer().serializeToString(m) : null
} Type guard
function isBareMxGraphModel(s: string): boolean {
return /^\s*(<\?xml[^>]*\?>\s*)?<mxGraphModel[\s>]/i.test(s)
} Try / catch
try { addPageToDoc(doc, { xml }) } catch (e) { if ((e as Error).message.includes('bare <mxGraphModel>')) { const m = extractFirstMxGraphModel(xml); if (m) addPageToDoc(doc, { xml: m }) else throw e } else throw e } Prevention
- Always unwrap to the page-level mxGraphModel before passing xml
- Prefer DOM extraction over regex/string slicing
- Write a small import helper so every call site is correct
When it happens
Trigger: Calling addPageToDoc(doc, { xml: fullDrawioFileString }) where the string's root element is <mxfile>, e.g. reusing the output of another file or of serializeToString on the whole document.
Common situations: Copy-pasting a .drawio file's contents as the xml option; piping output of one export directly into addPageToDoc; assuming the API accepts whole files rather than page fragments.
Related errors
- Page id "${id}" already exists
- ModelScope API error (${response.status}): ${errorText}
- Unexpected response format: ${contentType}
- Invalid preset name
- ${varName} must be a valid integer, got: ${value}
AI-assisted analysis of DayuanJiang/next-ai-draw-io@155ef4f7ac (2026-08-27).
Data as JSON: /api/errors/a9db271f46cabd31.
Report an issue: GitHub.