yewstack/yew · error

failed to remove child element

Error message

failed to remove child element

What it means

When a fragment unmounts, Yew removes every node it recorded as owning via parent.removeChild(node); removeChild returns NotFoundError when the node is no longer a child of that parent, and this expect turns that into a panic. Concretely, something modified the DOM underneath Yew: external code removed, replaced, or moved nodes inside the Yew-managed root without going through the virtual DOM, so Yew's bookkeeping no longer matches the live tree.

Source

Thrown at packages/yew/src/dom_bundle/fragment.rs:155

    /// Deeply clones all nodes.
    pub fn deep_clone(&self) -> Self {
        let nodes = self
            .iter()
            .map(|m| m.clone_node_with_deep(true).expect("failed to clone node."))
            .collect::<VecDeque<_>>();

        // the cloned nodes are disconnected from the real dom, so next_child is `None`
        Self(nodes, None)
    }

    // detaches current fragment.
    pub fn detach(self, _root: &BSubtree, parent: &Element, parent_to_detach: bool) {
        if !parent_to_detach {
            for node in self.iter() {
                parent
                    .remove_child(node)
                    .expect("failed to remove child element");
            }
        }
    }

    /// Shift current Fragment into a different position in the dom.
    pub fn shift(&self, next_parent: &Element, slot: DomSlot) -> DomSlot {
        for node in self.iter() {
            slot.insert(next_parent, node);
        }

        self.front().cloned().map(DomSlot::at).unwrap_or(slot)
    }

    /// Return the node that comes after all the nodes in this fragment
    pub fn sibling_at_end(&self) -> Option<&Node> {
        self.1.as_ref()
    }
}

View on GitHub (pinned to 0e4a05472f)

Solutions

  1. Audit every direct DOM write inside the Yew root: set_inner_html, remove, replace_with, append_child on managed nodes - and remove them
  2. Drive content changes through state + re-render instead of manual DOM edits
  3. Keep third-party scripts and extensions away from the app root, or confine them to elements Yew does not manage
  4. Where interop is unavoidable, let Yew render an empty wrapper and mutate only the inside of that wrapper from outside

Example fix

// before: destroying DOM Yew owns -> later detach panics with NotFoundError
if let Some(el) = node_ref.cast::<web_sys::HtmlElement>() {
    el.set_inner_html("");
}

// after: clear via state; Yew re-renders and unmounts cleanly
set_items(Vec::new());
Defensive patterns

Strategy: validation

Validate before calling

// Before mutating any node from outside Yew, confirm Yew did not create it:
fn is_safe_to_touch(el: &web_sys::Element, app_root: &str) -> bool {
    // Nodes inside the app root are managed by Yew - leave them alone
    el.closest(app_root).is_none()
}

Prevention

When it happens

Trigger: Calling set_inner_html(""), remove(), replace_with(), or append_child() on nodes Yew created (e.g. via a NodeRef cast to HtmlElement) so that at detach time Yew's recorded children are not attached to the recorded parent; third-party scripts or browser extensions rewriting regions of the page containing the app; teardown after a failed hydration already disturbed the tree.

Common situations: Clearing a container with innerHTML = '' before or instead of re-rendering; jQuery-style DOM manipulation inside the app root; ad/analytics scripts rewriting DOM; manually moving a Yew subtree to a different parent.

Related errors


AI-assisted analysis of yewstack/yew@0e4a05472f (2026-08-22). Data as JSON: /api/errors/cd4e47561f78aab4. Report an issue: GitHub.