{"record":{"id":"1212738598ed2260","repo":"DayuanJiang/next-ai-draw-io","slug":"error-replacing-nodes-error","errorCode":null,"errorMessage":"Error replacing nodes: ${error}","messagePattern":"Error replacing nodes: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/utils.ts","lineNumber":471,"sourceCode":"        if (!hasCell1) {\n            const cell1 = currentDoc.createElement(\"mxCell\")\n            cell1.setAttribute(\"id\", \"1\")\n            cell1.setAttribute(\"parent\", \"0\")\n\n            // Insert after cell0 if possible\n            const cell0 = currentRoot.querySelector('mxCell[id=\"0\"]')\n            if (cell0?.nextSibling) {\n                currentRoot.insertBefore(cell1, cell0.nextSibling)\n            } else {\n                currentRoot.appendChild(cell1)\n            }\n        }\n\n        // Convert the modified DOM back to a string\n        const serializer = new XMLSerializer()\n        return serializer.serializeToString(currentDoc)\n    } catch (error) {\n        throw new Error(`Error replacing nodes: ${error}`)\n    }\n}\n\n// ============================================================================\n// ID-based Diagram Operations\n// ============================================================================\n\nexport interface OperationError {\n    type: \"update\" | \"add\" | \"delete\"\n    cellId: string\n    message: string\n}\n\nexport interface ApplyOperationsResult {\n    result: string\n    errors: OperationError[]\n}\n","sourceCodeStart":453,"sourceCodeEnd":489,"githubUrl":"https://github.com/DayuanJiang/next-ai-draw-io/blob/155ef4f7acd29c9d46fb6fc35c92e6e6955a6ce1/lib/utils.ts#L453-L489","documentation":"replaceNodes wraps any failure while cloning, splicing, or re-serializing DOM nodes during XML mutation into a single catch-all 'Error replacing nodes: ${error}'. It is a re-throw that loses the original stack but preserves the cause's message. The underlying failure is usually a malformed XPath/selector, an orphaned node, or invalid XML produced by the edit.","triggerScenarios":"Calling replaceNodes (directly or via replacedXML) with node references that do not belong to the document being edited, an XPath that resolves to null/a non-element node, or input XML that failed to parse upstream so currentDoc is undefined.","commonSituations":"Programmatic draw.io/diagram XML editing pipelines where callers hold stale node handles after a previous mutation round-tripped through serializeToString; passing serialized strings back in without re-parsing; namespaces getting mangled by XMLSerializer.","solutions":["Log or inspect the wrapped 'error' value — the real cause (e.g. 'Failed to execute importNode' or 'The node to be replaced is not a child of this node') is in the appended message, not this wrapper","Verify each node you pass was obtained from the same parsed Document as currentDoc (re-parse after serializing)","Check that XPath/selector results are non-null elements before calling replaceNodes","Re-parse the XML string and retry once if nodes came from a previous serialization round-trip"],"exampleFix":"// before\nconst out = replacedXML(xml, [{ oldNode, newNode }]) // oldNode from a different doc\n\n// after\nconst doc = new DOMParser().parseFromString(xml, 'application/xml')\nconst oldNode = doc.querySelector('#target')\nif (!oldNode) throw new Error('target node not found')\nconst out = replaceNodes(doc, [{ oldNode, newNode: doc.importNode(newNode, true) }])","handlingStrategy":"validation","validationCode":"const doc = new DOMParser().parseFromString(xml, 'application/xml')\nif (doc.querySelector('parsererror')) throw new Error('input xml is malformed')\nconst targets = selectors.map(s => doc.querySelector(s))\nif (targets.some(t => !(t instanceof Element))) throw new Error('selector matched no element')","typeGuard":"function nodesBelongToDoc(doc: Document, nodes: (Node | null)[]): boolean {\n  return nodes.every(n => n != null && n.ownerDocument === doc)\n}","tryCatchPattern":"try {\n  result = replaceNodes(doc, ops)\n} catch (e) {\n  throw new Error(`replaceNodes failed for ops on ${docName}: ${e instanceof Error ? e.message : e}`)\n}","preventionTips":["Re-parse XML after every serialize round-trip before reusing node handles","Validate all selectors resolve to Elements before mutating","Never mix nodes from two different Documents; use doc.importNode"],"tags":["dom","xml","node-manipulation","wrapper-error"],"backgroundTag":"dom-node-manipulation-failed","analyzedSha":"155ef4f7acd29c9d46fb6fc35c92e6e6955a6ce1","analyzedAt":"2026-08-27T11:40:38.297Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}