bevyengine/bevy · error
Cannot find element: {selector}.
Error message
Cannot find element: {selector}. What it means
The wasm counterpart of a valid-but-unmatched selector: in winit_windows, document.querySelector succeeded syntactically but returned null, so bevy panics "Cannot find element: {selector}.". The selector is fine; the HTML document simply contains no element matching it at the time the window was created.
Source
Thrown at crates/bevy_winit/src/winit_windows.rs:284
)]
let mut winit_window_attributes = winit_window_attributes.with_title(window.title.as_str());
#[cfg(target_arch = "wasm32")]
{
use wasm_bindgen::JsCast;
use winit::platform::web::WindowAttributesExtWebSys;
if let Some(selector) = &window.canvas {
let window = web_sys::window().unwrap();
let document = window.document().unwrap();
let canvas = document
.query_selector(selector)
.expect("Cannot query for canvas element.");
if let Some(canvas) = canvas {
let canvas = canvas.dyn_into::<web_sys::HtmlCanvasElement>().ok();
winit_window_attributes = winit_window_attributes.with_canvas(canvas);
} else {
panic!("Cannot find element: {selector}.");
}
}
winit_window_attributes =
winit_window_attributes.with_prevent_default(window.prevent_default_event_handling);
winit_window_attributes = winit_window_attributes.with_append(true);
}
let winit_window = event_loop.create_window(winit_window_attributes).unwrap();
let name = window.title.clone();
prepare_accessibility_for_window(
event_loop,
&winit_window,
entity,
name,
accessibility_requested.clone(),
adapters,
handlers,View on GitHub (pinned to 396ca72708)
Solutions
- Add the matching element to the HTML host page: <canvas id="game-canvas"></canvas>.
- Load the wasm binary after DOM readiness — put the script at the end of <body> or use defer/module scripts.
- Double-check exact spelling and case of the id/class on both sides.
- If the canvas is inserted dynamically, wait for it to exist before spawning the Window (e.g. gate app start on a JS readiness signal).
Example fix
<!-- before: index.html missing the element --> <body><script src="pkg/my_game.js"></script></body> <!-- after: canvas exists and script runs after it --> <body> <canvas id="game-canvas"></canvas> <script type="module" src="pkg/my_game.js"></script> </body>
Defensive patterns
Strategy: validation
Validate before calling
#[cfg(target_arch = "wasm32")]
fn canvas_exists(selector: &str) -> bool {
web_sys::window()
.and_then(|w| w.document())
.and_then(|d| d.query_selector(selector).ok().flatten()) // Ok(None) = no match
.is_some()
}
// gate window creation on DOM readiness
if !canvas_exists("#game-canvas") {
web_sys::console::warn_1(&"#game-canvas missing — check index.html".into());
} Try / catch
// Panic happens during window creation; probe the DOM first and defer the Window // (or fall back to Bevy-created canvas) when the element is absent.
Prevention
- Load the wasm module after the canvas element (end of body, defer, or module script).
- Keep the canvas id in one place; update HTML and Rust together.
- For dynamically inserted canvases, start the app from a DOM-ready callback.
When it happens
Trigger: Window { canvas: Some("#game-canvas".into()) } while index.html has no <canvas id="game-canvas">; a typo'd or renamed id; the wasm module executing before the DOM is parsed (script in <head> without defer); canvas existing only after JS dynamically inserts it later.
Common situations: Web builds where the script tag placement changed; renaming the canvas in HTML but not in Rust (or vice versa); frameworks that render the host page asynchronously; copy-pasting index.html templates that use a different id.
Related errors
- Cannot query for canvas element.
- window.canvas() can only be called in main thread.
- Attempted to insert invalid value of type {}.
- Attempted to push invalid value of type {}.
- Attempted to insert invalid value of type {}.
AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20).
Data as JSON: /api/errors/f725bdd8cd068f0d.
Report an issue: GitHub.