can1357/oh-my-pi · error · Error
The node to replace is not a child of this node
Error message
The node to replace is not a child of this node
What it means
Node.replaceChild(child, previous) requires `previous` to be an existing direct child of the node; `this.childNodes.indexOf(previous)` returning -1 throws this error before any mutation. This mirrors the standard DOM NotFoundError behavior — you can only replace a node that is actually a child of the receiver.
Source
Thrown at packages/utils/src/dom/core.ts:228
insertBefore<T extends Node>(child: T, reference: Node | null): T {
if (reference === null) return this.appendChild(child);
const index = this.childNodes.indexOf(reference);
if (index < 0) throw new Error("The reference node is not a child of this node");
if (child instanceof DocumentFragment) {
for (const nested of [...child.childNodes]) this.insertBefore(nested, reference);
return child;
}
child.parentNode?.removeChild(child);
child.parentNode = this;
child.setOwnerDocument(this.documentForCreation());
this.childNodes.splice(index, 0, child);
return child;
}
/** Replace a current child with another node. */
replaceChild<T extends Node>(child: Node, previous: T): T {
const index = this.childNodes.indexOf(previous);
if (index < 0) throw new Error("The node to replace is not a child of this node");
this.removeChild(previous);
this.insertBefore(child, this.childNodes[index] ?? null);
return previous;
}
/** Remove a current child. */
removeChild<T extends Node>(child: T): T {
const index = this.childNodes.indexOf(child);
if (index < 0) throw new Error("The node to remove is not a child of this node");
this.childNodes.splice(index, 1);
child.parentNode = null;
return child;
}
/** Replace all children with nodes or strings. */
replaceChildren(...children: Array<Node | string>): void {
for (const child of this.childNodes) child.parentNode = null;
this.childNodes = [];View on GitHub (pinned to 9690622007)
Solutions
- Assert `oldChild.parentNode === parent` before replaceChild; if it's null, the node is already detached.
- Check argument order: signature is replaceChild(newChild, oldChild) — the node being replaced goes second.
- If the node may already be gone, guard with a membership check or catch and fall back to appendChild/removeChild accordingly.
- Re-query the live child (by index or querySelector) instead of reusing a node captured before prior mutations.
Example fix
// before: swapped/invalid previous
parent.replaceChild(oldChild, newChild); // throws: oldChild is not a child
// after: correct order plus guard
if (oldChild.parentNode === parent) {
parent.replaceChild(newChild, oldChild);
} Defensive patterns
Strategy: validation
Validate before calling
if (oldChild.parentNode === parent) {
parent.replaceChild(newChild, oldChild);
} Type guard
function isReplaceable(parent: Node, oldChild: Node): boolean {
return parent.childNodes.includes(oldChild);
} Try / catch
try {
parent.replaceChild(newChild, oldChild);
} catch (err) {
if (err instanceof Error && err.message === "The node to replace is not a child of this node") {
// already detached or wrong parent — decide: append instead or skip
parent.appendChild(newChild);
} else {
throw err;
}
} Prevention
- Remember argument order: replaceChild(newChild, oldChild) — the replaced node goes second.
- Verify oldChild.parentNode === parent before replacing; stale references after removals are the top cause.
- Never reuse nodes from cloned/detached subtrees as replacement targets; re-query the live tree.
When it happens
Trigger: Calling `parent.replaceChild(newChild, oldChild)` where `oldChild` was already removed, was never a child of `parent`, or belongs to another parent/subtree; calling with swapped arguments so the 'previous' slot holds the new node.
Common situations: Replacing a node after a prior removal/move made the reference stale; using a node from a cloned/detached subtree; argument-order mistakes (child vs previous) in code ports from other DOM implementations; batch updates that replace the same node twice.
Related errors
- The reference node is not a child of this node
- The node to remove is not a child of this node
- The new child is an ancestor of this node
- unknown function: {0}
- unknown key binding function: {0}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/7b07a028994a74ca.
Report an issue: GitHub.