iced-rs/iced · critical
Append canvas to HTML body
Error message
Append canvas to HTML body
What it means
On wasm32, after obtaining the window canvas the runtime appends it to the document body and expects the DOM append_child call to succeed. append_child returns an Err (HierarchyRequestError or similar) when the body element is missing or the node cannot be attached; iced cannot display anything without the canvas in the DOM, so it panics.
Source
Thrown at winit/src/lib.rs:374
let document = window.document().unwrap();
let body = document.body().unwrap();
let target = target.and_then(|target| {
body.query_selector(&format!("#{target}"))
.ok()
.unwrap_or(None)
});
match target {
Some(node) => {
let _ = node.replace_with_with_node_1(&canvas).expect(
&format!("Could not replace #{}", node.id()),
);
}
None => {
let _ = body
.append_child(&canvas)
.expect("Append canvas to HTML body");
}
};
}
self.process_event(
event_loop,
Event::WindowCreated {
id,
window: Arc::new(window),
exit_on_close_request,
make_visible: visible,
on_open,
},
);
}
Control::Exit => {
self.process_event(event_loop, Event::Exit);
event_loop.exit();View on GitHub (pinned to d146509d89)
Solutions
- Load the wasm entry point after the DOM is ready: use <script type="module">, defer, or wait for the load event before calling the iced runner.
- Ensure the HTML document has a valid <body> element at startup.
- If a #container node lookup fails upstream, verify the element id in HTML matches what the app queries before the append_child fallback runs.
- Pin compatible iced/winit versions; the DOM mounting logic changed across releases.
Example fix
// before (html) <head><script src="app.js"></script></head> // after (html) <body><script type="module" src="app.js"></script></body>
Defensive patterns
Strategy: validation
Validate before calling
// only mount after the document body exists
if (document.readyState === "loading") {
await new Promise(r => document.addEventListener("DOMContentLoaded", r));
}
if (!document.body) throw new Error("document.body missing; cannot mount canvas"); Type guard
function bodyReady(): boolean {
return document.readyState !== "loading" && document.body !== null;
} Try / catch
try {
body.appendChild(canvas);
} catch (e) {
console.error("Canvas mount failed; is <body> present and parsed?", e);
} Prevention
- Load the wasm entry with type="module" or defer so <body> exists.
- Never bootstrap the GUI from <head> without deferral.
- Confirm the container element id matches the app's query before relying on the append fallback.
- Pin compatible iced/winit versions for the web target.
When it happens
Trigger: Calling run on wasm when document.body() is None (script executed before <body> exists or in a non-HTML context), or when the canvas node cannot be a child of body (wrong node type/already-attached hierarchy issue).
Common situations: WASM module loaded in <head> without defer, so body doesn't exist yet; using a custom loader that runs before the document finishes parsing; page contexts where body was replaced during startup.
Related errors
AI-assisted analysis of iced-rs/iced@d146509d89 (2026-09-11).
Data as JSON: /api/errors/3938b609cb852853.
Report an issue: GitHub.