{"record":{"id":"7d72bf4d021704f5","repo":"GraphiteEditor/Graphite","slug":"failed-to-get-canvas-context-7d72bf","errorCode":null,"errorMessage":"Failed to get canvas context","messagePattern":"Failed to get canvas context","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"editor/src/messages/portfolio/document/overlays/utility_functions.rs","lineNumber":30,"sourceCode":"use std::collections::HashMap;\n#[cfg(target_family = \"wasm\")]\nuse wasm_bindgen::JsCast;\n\n#[cfg(target_family = \"wasm\")]\npub fn overlay_canvas_element() -> Option<web_sys::HtmlCanvasElement> {\n\tlet window = web_sys::window()?;\n\tlet document = window.document()?;\n\tlet canvas = document.query_selector(\"[data-overlays-canvas]\").ok().flatten()?;\n\tcanvas.dyn_into::<web_sys::HtmlCanvasElement>().ok()\n}\n\n#[cfg(target_family = \"wasm\")]\npub fn overlay_canvas_context() -> web_sys::CanvasRenderingContext2d {\n\tlet create_context = || {\n\t\tlet context = overlay_canvas_element()?.get_context(\"2d\").ok().flatten()?;\n\t\tcontext.dyn_into().ok()\n\t};\n\tcreate_context().expect(\"Failed to get canvas context\")\n}\n\npub fn selected_segments(network_interface: &NodeNetworkInterface, shape_editor: &ShapeState) -> HashMap<LayerNodeIdentifier, Vec<SegmentId>> {\n\tlet mut map = HashMap::new();\n\n\tfor (layer, state) in &shape_editor.selected_shape_state {\n\t\tlet Some(vector) = network_interface.compute_modified_vector(*layer) else { continue };\n\t\tlet selected_segments = selected_segments_for_layer(&vector, state);\n\n\t\tmap.insert(*layer, selected_segments);\n\t}\n\n\tmap\n}\n\npub fn selected_segments_for_layer(vector: &Vector, state: &SelectedLayerState) -> Vec<SegmentId> {\n\tlet selected_anchors = state\n\t\t.selected_points()","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/editor/src/messages/portfolio/document/overlays/utility_functions.rs#L12-L48","documentation":"WASM-only helper overlay_canvas_context(): it locates the overlays canvas via overlay_canvas_element() (which returns None when window, document, or the [data-overlays-canvas] element is missing) and then demands a 2D context. The ? chain covers the element being absent, but .expect(\"Failed to get canvas context\") panics when the element exists yet get_context(\"2d\") yields null or the returned object fails dyn_into::<CanvasRenderingContext2d>() — the same one-context-per-canvas browser rule as the message-handler path.","triggerScenarios":"Overlay drawing utilities invoked while the overlays canvas element exists but its context was already claimed as webgl/webgpu, or 2D context creation fails; also when a non-2D context object comes back so dyn_into errors.","commonSituations":"Embedders or integrations reusing the overlay canvas for WebGL; headless/test environments where canvas contexts are unavailable; DOM changes removing or duplicating the overlays canvas element.","solutions":["Make overlay_canvas_context return Option<CanvasRenderingContext2d> and let callers skip overlay drawing on None.","Ensure nothing else requests a non-2D context from the [data-overlays-canvas] element.","Log a warning instead of panicking so the overlay layer degrades without crashing the app.","Re-query the canvas element when the context lookup fails, in case the DOM node was replaced."],"exampleFix":"// before\ncreate_context().expect(\"Failed to get canvas context\")\n\n// after\npub fn overlay_canvas_context() -> Option<web_sys::CanvasRenderingContext2d> {\n\tlet context = overlay_canvas_element()?.get_context(\"2d\").ok().flatten()?;\n\tcontext.dyn_into().ok()\n}\n// callers: let Some(ctx) = overlay_canvas_context() else { return; };","handlingStrategy":"validation","validationCode":"// make absence explicit and checkable\nfn try_overlay_canvas_context() -> Option<web_sys::CanvasRenderingContext2d> {\n\tlet context = overlay_canvas_element()?.get_context(\"2d\").ok().flatten()?;\n\tcontext.dyn_into().ok()\n}\n// caller: if try_overlay_canvas_context().is_none() { skip overlay drawing }","typeGuard":"fn overlay_context_available() -> bool {\n\tweb_sys::window().is_some()\n\t\t&& overlay_canvas_element()\n\t\t\t.and_then(|c| c.get_context(\"2d\").ok().flatten())\n\t\t\t.is_some()\n}","tryCatchPattern":"match create_context() {\n\tSome(ctx) => ctx,\n\tNone => {\n\t\tlog::warn!(\"Overlay canvas 2D context unavailable\");\n\t\treturn;\n\t}\n}","preventionTips":["Return Option from context helpers instead of panicking inside them","Reserve the [data-overlays-canvas] element exclusively for the 2D overlay layer","In headless tests, stub or skip overlay drawing rather than exercising real canvas contexts"],"tags":["wasm","canvas-2d","dom","overlay","panic"],"backgroundTag":"canvas-2d-context-null","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}