yewstack/yew · error

failed to clone node.

Error message

failed to clone node.

What it means

During hydration, Yew re-parents server-rendered nodes and deep-clones each node of a fragment with clone_node_with_deep(true); this expect fires when the browser refuses to deep-clone one of those nodes. Because Yew itself created or adopted these nodes, a failure normally comes from page content that does not survive a deep clone - custom elements whose constructors throw, or node types with clone restrictions in the target engine - rather than from component logic.

Source

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

    /// Remove child nodes until first non-text node.
    pub fn trim_start_text_nodes(&mut self) {
        while let Some(ref m) = self.front().cloned() {
            if m.node_type() == Node::TEXT_NODE {
                self.pop_front();

                m.unchecked_ref::<web_sys::Text>().remove();
            } else {
                break;
            }
        }
    }

    /// 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.

View on GitHub (pinned to 0e4a05472f)

Solutions

  1. Bisect the page: hydrate progressively smaller subtrees until the failing element is isolated
  2. Test the suspect markup in the console with document.querySelector('<sel>').cloneNode(true) - a throw identifies the culprit
  3. Move the non-clonable widget outside the hydrated region and mount it client-side after hydration completes
  4. If an ordinary element fails to deep-clone, file a Yew issue with the SSR HTML and a repro
Defensive patterns

Strategy: validation

Validate before calling

// Before hydrating a page containing third-party widgets, verify the markup clones:
// document.querySelector('#widget-host').cloneNode(true)
// If that throws in the console, exclude the region from hydration.

Prevention

When it happens

Trigger: Calling Renderer::hydrate() over SSR HTML whose hydrated region contains web components with throwing constructors or other non-clonable nodes; hydration inside engines with partial cloneNode(true) support.

Common situations: Third-party widgets (editors, maps, analytics) embedded in server-rendered pages that are later hydrated; older mobile webviews; SSR output that injected unusual nodes into the tree.

Related errors


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