{"record":{"id":"d1211156c821e18c","repo":"GraphiteEditor/Graphite","slug":"failed-to-create-canvas-element","errorCode":null,"errorMessage":"Failed to create canvas element","messagePattern":"Failed to create canvas element","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/wrapper/src/helpers.rs","lineNumber":164,"sourceCode":"\t\t\t}\n\t\t\tnew_obj.into()\n\t\t}\n\t};\n\tlet canvases_obj = Object::from(canvases_obj);\n\n\tfor image in image_data {\n\t\tlet (placeholder_id, width, height) = (image.id, image.width, image.height);\n\t\tlet pixels = image.pixels.as_slice();\n\t\tlet canvas_name = placeholder_id.to_string();\n\t\tlet js_key = JsValue::from_str(&canvas_name);\n\n\t\tif Reflect::has(&canvases_obj, &js_key).unwrap_or(false) || width == 0 || height == 0 {\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet canvas: HtmlCanvasElement = document\n\t\t\t.create_element(\"canvas\")\n\t\t\t.expect(\"Failed to create canvas element\")\n\t\t\t.dyn_into::<HtmlCanvasElement>()\n\t\t\t.expect(\"Failed to cast element to HtmlCanvasElement\");\n\n\t\tcanvas.set_width(width);\n\t\tcanvas.set_height(height);\n\n\t\tlet context: CanvasRenderingContext2d = canvas\n\t\t\t.get_context(\"2d\")\n\t\t\t.expect(\"Failed to get 2d context\")\n\t\t\t.expect(\"2d context was not found\")\n\t\t\t.dyn_into::<CanvasRenderingContext2d>()\n\t\t\t.expect(\"Failed to cast context to CanvasRenderingContext2d\");\n\t\tlet clamped_pixels = wasm_bindgen::Clamped(pixels);\n\t\tmatch ImageData::new_with_u8_clamped_array_and_sh(clamped_pixels, width, height) {\n\t\t\tOk(image_data_obj) => {\n\t\t\t\tif context.put_image_data(&image_data_obj, 0, 0).is_err() {\n\t\t\t\t\terror!(\"Failed to put image data on canvas for id: {placeholder_id}\");\n\t\t\t\t}","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/frontend/wrapper/src/helpers.rs#L146-L182","documentation":"While blitting each rasterized image, the helper calls `document.create_element(\"canvas\")`, which returns `Result<Element, JsValue>` because the DOM method can throw (e.g. `InvalidCharacterError`). The `.expect(\"Failed to create canvas element\")` panics on that. Since \"canvas\" is always a valid tag name in an HTML document, an `Err` here means the document isn't a normal HTML document (XML/SVG document, polyfilled DOM) or the environment is a partial mock.","triggerScenarios":"`render_image_data_to_canvases` running against a document created by `document.implementation.createDocument(null, ...)` (XML mode), a DOM emulation where `createElement` throws or is missing, or a page whose `document` global was replaced.","commonSituations":"Embedding the editor's canvas blitting in test environments (jsdom variants, happy-dom) or non-HTML host documents; SSR shims with incomplete DOM APIs; rare custom-element registries that throw during creation.","solutions":["Replace the `.expect` with `match`/`let-else` that logs the image id and `continue`s to the next image, matching the graceful style of the surrounding code.","In tests, run against a real browser DOM instead of partial mocks.","Ensure the host page is a standard HTML document (no XHTML/XML document mode) where the wrapper is mounted.","Probe once at startup: `document.createElement('canvas')` succeeds before enabling image-blitting paths."],"exampleFix":"// before\nlet canvas: HtmlCanvasElement = document\n  .create_element(\"canvas\")\n  .expect(\"Failed to create canvas element\")\n  .dyn_into::<HtmlCanvasElement>()\n  .expect(\"Failed to cast element to HtmlCanvasElement\");\n\n// after\nlet canvas = match document.create_element(\"canvas\") {\n  Ok(element) => element,\n  Err(err) => {\n    error!(\"create_element('canvas') threw {err:?} for image id {placeholder_id}\");\n    continue;\n  }\n};\nlet Ok(canvas) = canvas.dyn_into::<HtmlCanvasElement>() else {\n  error!(\"created element is not an HTMLCanvasElement for image id {placeholder_id}\");\n  continue;\n};","handlingStrategy":"validation","validationCode":"// TS: startup probe that createElement works before relying on image blitting\nexport const domCanCreateCanvas: boolean = (() => {\n  try {\n    return document.createElement('canvas') instanceof HTMLCanvasElement;\n  } catch {\n    return false;\n  }\n})();","typeGuard":null,"tryCatchPattern":"JS cannot catch the wasm panic; gate blitting on the startup probe above and check `await editor.hasCrashed()` if the editor stops responding.","preventionTips":["Run in a real browser DOM; if using jsdom, configure it fully.","Ensure the host document is HTML mode, not XML/SVG."],"tags":["dom","createelement","wasm","panic","canvas"],"backgroundTag":"dom-createelement-threw","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}