can1357/oh-my-pi · error · Error
The node to remove is not a child of this node
Error message
The node to remove is not a child of this node
What it means
Node.removeChild looks up the child in `this.childNodes` and throws when it is not found (indexOf === -1). A node can only be removed from its actual current parent; calling removeChild with a node that is detached or parented elsewhere throws this error, matching the standard DOM's NotFoundError.
Source
Thrown at packages/utils/src/dom/core.ts:237
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 = [];
this.append(...children);
}
/** Append nodes or strings. */
append(...children: Array<Node | string>): void {
for (const child of children) {
this.appendChild(typeof child === "string" ? this.documentForCreation().createTextNode(child) : child);
}
}View on GitHub (pinned to 9690622007)
Solutions
- Check `child.parentNode` first and remove from `child.parentNode` (or skip if null) instead of a captured parent reference.
- Guard double removals: `if (child.parentNode) child.parentNode.removeChild(child);`
- If iterating while removing, iterate over a snapshot `[...parent.childNodes]` or loop by index from the end.
- Wrap disposal logic so it is idempotent — mark nodes as removed or rely on parentNode nullness.
Example fix
// before: removes from captured parent, may double-remove parent.removeChild(child); // throws if child moved or already removed // after: remove from the node's actual parent, idempotently child.parentNode?.removeChild(child);
Defensive patterns
Strategy: validation
Validate before calling
if (child.parentNode) {
child.parentNode.removeChild(child);
} Type guard
function isAttachedChild(parent: Node, child: Node): child is Node & { parentNode: Node } {
return parent.childNodes.includes(child);
} Try / catch
try {
parent.removeChild(child);
} catch (err) {
if (err instanceof Error && err.message === "The node to remove is not a child of this node") {
// idempotent cleanup: already removed or moved — ignore
} else {
throw err;
}
} Prevention
- Always remove via `child.parentNode?.removeChild(child)` so parent and child always agree.
- Make dispose/cleanup paths idempotent — check parentNode before removing to survive double teardown.
- Iterate over a snapshot (`[...parent.childNodes]`) when removing many children.
When it happens
Trigger: Calling `parent.removeChild(child)` where `child.parentNode !== parent` — child already removed (double removal), child belongs to another parent, or child/parent arguments are inconsistent; also reached indirectly via replaceChild, which calls removeChild internally.
Common situations: Cleanup loops that remove the same node twice (e.g. in clear + dispose paths); removing a node from a captured parent after the node was re-parented; removing nodes during iteration over childNodes without accounting for mutation; event/dispose handlers racing each other.
Related errors
- The reference node is not a child of this node
- The node to replace 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/6c9ee12dd0c3d4da.
Report an issue: GitHub.