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
- Bisect the page: hydrate progressively smaller subtrees until the failing element is isolated
- Test the suspect markup in the console with document.querySelector('<sel>').cloneNode(true) - a throw identifies the culprit
- Move the non-clonable widget outside the hydrated region and mount it client-side after hydration completes
- 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
- Keep web components and other exotic nodes outside the hydrated region; mount them client-side after hydration
- Smoke-test cloneNode(true) on SSR output when adding new third-party markup
- Prefer hydrating regions that contain only standard HTML produced by your own components
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
- couldn't clone cached element
- couldn't clone node to be cached
- failed to deserialize state
- this hook takes 2 arguments but 1 argument was supplied
- this hook takes 2 arguments but 1 argument was supplied
AI-assisted analysis of yewstack/yew@0e4a05472f (2026-08-22).
Data as JSON: /api/errors/0e0a12434ef7ea60.
Report an issue: GitHub.