{"record":{"id":"dfec7cca748dc43f","repo":"DayuanJiang/next-ai-draw-io","slug":"addpagetodoc-opts-xml-must-be-a-bare-mxgraphmode-dfec7c","errorCode":null,"errorMessage":"addPageToDoc: opts.xml must be a bare <mxGraphModel>.","messagePattern":"addPageToDoc: opts\\.xml must be a bare <mxGraphModel>\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/mcp-server/src/pages.ts","lineNumber":263,"sourceCode":"        if (isMxFile(trimmed)) {\n            throw new Error(\n                \"addPageToDoc: opts.xml must be a bare <mxGraphModel>; received a full <mxfile>. Extract the target diagram's <mxGraphModel> first.\",\n            )\n        }\n        if (!isMxGraphModel(trimmed)) {\n            throw new Error(\n                \"addPageToDoc: opts.xml must be a bare <mxGraphModel>.\",\n            )\n        }\n        inner = trimmed\n    } else {\n        inner = `<mxGraphModel><root><mxCell id=\"0\"/><mxCell id=\"1\" parent=\"0\"/></root></mxGraphModel>`\n    }\n\n    const snippet = `<wrapper><diagram id=\"${escapeAttr(id)}\" name=\"${escapeAttr(name)}\">${inner}</diagram></wrapper>`\n    const tempDoc = new DOMParser().parseFromString(snippet, \"text/xml\")\n    if (tempDoc.querySelector(\"parsererror\")) {\n        throw new Error(\n            \"Failed to parse new page xml — make sure it is a valid <mxGraphModel>\",\n        )\n    }\n    const newDiagram = tempDoc.querySelector(\"diagram\")\n    if (!newDiagram) {\n        throw new Error(\"Failed to construct <diagram> element for new page\")\n    }\n\n    const imported = doc.importNode(newDiagram, true) as Element\n    doc.documentElement.appendChild(imported)\n\n    return {\n        id,\n        name,\n        index: existing.length,\n        cellCount: imported.querySelectorAll(\"mxCell\").length,\n    }\n}","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/DayuanJiang/next-ai-draw-io/blob/155ef4f7acd29c9d46fb6fc35c92e6e6955a6ce1/packages/mcp-server/src/pages.ts#L245-L281","documentation":"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.","triggerScenarios":"Passing opts.xml containing raw '&' or '<' in attributes/values (e.g. a label 'A & B'), truncated markup, or HTML-style entities like &nbsp; that strict XML parsing rejects.","commonSituations":"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.","solutions":["Escape dynamic text with escapeAttr/escapeXml-equivalents before embedding in XML","Validate opts.xml parses standalone before calling addPageToDoc","Replace HTML-only entities (&nbsp;) with numeric XML equivalents (&#160;) or wrap labels as ...escaped HTML per mxGraph conventions","If concatenating, use DOM APIs (createElement/setTextContent) instead of strings"],"exampleFix":"// before\naddPageToDoc(doc, { xml: `<mxGraphModel><root><mxCell value=\"A & B\" .../></root></mxGraphModel>` })\n\n// after\nconst value = 'A &amp; B'\naddPageToDoc(doc, { xml: `<mxGraphModel><root><mxCell value=\"${value}\" .../></root></mxGraphModel>` })","handlingStrategy":"validation","validationCode":"const probe = new DOMParser().parseFromString(opts.xml, 'text/xml')\nif (probe.querySelector('parsererror')) {\n  throw new Error('opts.xml is not well-formed XML; escape entities/quotes first')\n}","typeGuard":"function isWellFormedXml(s: string): boolean {\n  return !new DOMParser().parseFromString(s, 'text/xml').querySelector('parsererror')\n}","tryCatchPattern":"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 }","preventionTips":["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"],"tags":["drawio","xml","escaping","parsing"],"backgroundTag":"malformed-xml-input","analyzedSha":"155ef4f7acd29c9d46fb6fc35c92e6e6955a6ce1","analyzedAt":"2026-08-27T11:40:38.297Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}