DayuanJiang/next-ai-draw-io · error · Error
Page id "${id}" already exists
Error message
Page id "${id}" already exists What it means
addPageToDoc refuses to create a page whose id collides with an existing page in the same document. Page ids must be unique inside an <mxfile> because draw.io addresses pages by id for navigation and links. The check compares opts.id against listPagesFromDoc(doc).
Source
Thrown at packages/mcp-server/src/pages.ts:238
* Append a new <diagram> to the mxfile doc. The new page's model defaults to
* an empty <mxGraphModel><root><mxCell id="0"/><mxCell id="1" parent="0"/></root></mxGraphModel>.
*
* `opts.xml` must be a BARE <mxGraphModel> — passing a full <mxfile> would
* end up nested inside <diagram>, which is malformed. We reject the mxfile
* shape explicitly and strip any <?xml ?> declaration (only valid at
* document start, never inside <diagram>).
*
* 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 {View on GitHub (pinned to 155ef4f7ac)
Solutions
- Omit opts.id and let generatePageId() assign a unique id
- If the id matters, check first: listPagesFromDoc(doc).some(p => p.id === myId) and skip or use a suffix
- If importing pages, prefix or remap ids to avoid collisions
- If the script may re-run, make it idempotent by checking for the page before adding
Example fix
// before
addPageToDoc(doc, { id: 'spec', name: 'Spec' }) // throws if 'spec' exists
// after
if (!listPagesFromDoc(doc).some(p => p.id === 'spec')) {
addPageToDoc(doc, { id: 'spec', name: 'Spec' })
} Defensive patterns
Strategy: type-guard
Validate before calling
import { listPagesFromDoc, addPageToDoc } from './pages'
const ids = new Set(listPagesFromDoc(doc).map(p => p.id))
if (ids.has(wantedId)) throw new Error(`page id ${wantedId} taken; choose another`) Type guard
function pageIdAvailable(doc: Document, id: string): boolean {
return !listPagesFromDoc(doc).some(p => p.id === id)
} Try / catch
try { addPageToDoc(doc, { id }) } catch (e) { if ((e as Error).message.includes('already exists')) addPageToDoc(doc, { id: `${id}-${Date.now()}` }) else throw e } Prevention
- Omit id to use generated unique ids
- Make import scripts idempotent: check-then-add
- Remap/prefix ids when copying pages between files
When it happens
Trigger: Calling addPageToDoc(doc, { id: 'page-1' }) when a page with id 'page-1' already exists; using a fixed/hardcoded id in a loop; re-running a script against a document it already mutated.
Common situations: Import scripts that copy pages from one file to another preserving ids; idempotent-looking scripts run twice; deterministic id generation (e.g. slug of page name) colliding with existing pages.
Related errors
- addPageToDoc: opts.xml must be a bare <mxGraphModel>; receiv
- Failed to construct <diagram> element for new page
- ModelScope API error (${response.status}): ${errorText}
- Unexpected response format: ${contentType}
- Invalid preset name
AI-assisted analysis of DayuanJiang/next-ai-draw-io@155ef4f7ac (2026-08-27).
Data as JSON: /api/errors/692a14dfb2da7e29.
Report an issue: GitHub.