{"record":{"id":"59a81705401b3567","repo":"bevyengine/bevy","slug":"cannot-query-for-canvas-element","errorCode":null,"errorMessage":"Cannot query for canvas element.","messagePattern":"Cannot query for canvas element\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/bevy_winit/src/winit_windows.rs","lineNumber":279,"sourceCode":"\n        #[expect(clippy::allow_attributes, reason = \"`unused_mut` is not always linted\")]\n        #[allow(\n            unused_mut,\n            reason = \"This variable needs to be mutable if `cfg(target_arch = \\\"wasm32\\\")`\"\n        )]\n        let mut winit_window_attributes = winit_window_attributes.with_title(window.title.as_str());\n\n        #[cfg(target_arch = \"wasm32\")]\n        {\n            use wasm_bindgen::JsCast;\n            use winit::platform::web::WindowAttributesExtWebSys;\n\n            if let Some(selector) = &window.canvas {\n                let window = web_sys::window().unwrap();\n                let document = window.document().unwrap();\n                let canvas = document\n                    .query_selector(selector)\n                    .expect(\"Cannot query for canvas element.\");\n                if let Some(canvas) = canvas {\n                    let canvas = canvas.dyn_into::<web_sys::HtmlCanvasElement>().ok();\n                    winit_window_attributes = winit_window_attributes.with_canvas(canvas);\n                } else {\n                    panic!(\"Cannot find element: {selector}.\");\n                }\n            }\n\n            winit_window_attributes =\n                winit_window_attributes.with_prevent_default(window.prevent_default_event_handling);\n            winit_window_attributes = winit_window_attributes.with_append(true);\n        }\n\n        let winit_window = event_loop.create_window(winit_window_attributes).unwrap();\n        let name = window.title.clone();\n        prepare_accessibility_for_window(\n            event_loop,\n            &winit_window,","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/bevyengine/bevy/blob/396ca727080776bd313bb892423b7d94e03b81b4/crates/bevy_winit/src/winit_windows.rs#L261-L297","documentation":"On wasm32, when Window.canvas is set to a CSS selector string, bevy_winit's winit_windows passes it to document.querySelector(selector) and .expect(\"Cannot query for canvas element.\"). An unparsable selector throws a DOM SyntaxError which web_sys surfaces as Err — i.e. this panic means the selector string itself is malformed, before any element lookup happens.","triggerScenarios":"Setting Window { canvas: Some(\"my-canvas\".into()) } without the '#' id prefix or '.' class prefix; selectors with stray characters, unbalanced brackets, or empty strings that still pass Some(\"\").","commonSituations":"Copy-pasting an element id into the canvas field as if it were a raw id rather than a CSS selector; dynamically building selector strings that end up empty or malformed; following examples for older Bevy versions where the field took an id.","solutions":["Write a valid CSS selector: prefix ids with '#' (e.g. \"#my-canvas\") and classes with '.'.","If targeting a class, ensure it is uniquely applied or made specific enough (\"canvas.game\").","Validate dynamically built selectors before assigning them to Window.canvas.","Remember an empty Some(\"\") string is also invalid — use None to let Bevy create its own canvas."],"exampleFix":"// before\nWindow {\n    canvas: Some(\"my-canvas\".into()), // invalid CSS selector -> panic\n    ..default()\n}\n\n// after\nWindow {\n    canvas: Some(\"#my-canvas\".into()), // id selector\n    ..default()\n}","handlingStrategy":"validation","validationCode":"#[cfg(target_arch = \"wasm32\")]\nfn selector_is_valid(selector: &str) -> bool {\n    web_sys::window()\n        .and_then(|w| w.document())\n        .map(|d| d.query_selector(selector).is_ok()) // Err = SyntaxError from a bad selector\n        .unwrap_or(false)\n}","typeGuard":"fn as_canvas_selector(s: &str) -> Option<&str> {\n    let valid = !s.is_empty() && s.starts_with(['#', '.']);\n    valid.then_some(s)\n}","tryCatchPattern":"// The expect() panics before any Result escapes; validate the selector string\n// (and its match, see error 856) before assigning Window.canvas.","preventionTips":["Prefix ids with '#' and classes with '.' — never pass a bare element id.","Centralize the selector string in one constant shared by HTML and Rust.","Use None rather than Some(\"\") to request Bevy's own canvas."],"tags":["rust","bevy","wasm","windowing","css-selector","dom","panic"],"backgroundTag":"invalid-css-selector","analyzedSha":"396ca727080776bd313bb892423b7d94e03b81b4","analyzedAt":"2026-08-20T16:12:39.808Z","contentChangedAt":"2026-08-20T16:12:39.808Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}