{"record":{"id":"50a6bea92cf26d82","repo":"GraphiteEditor/Graphite","slug":"window-should-have-a-document","errorCode":null,"errorMessage":"window should have a document","messagePattern":"window should have a document","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/wrapper/src/helpers.rs","lineNumber":135,"sourceCode":"pub(crate) fn async_wake_callback() -> Wake {\n\tuse std::sync::Arc;\n\tArc::new(|| {\n\t\twasm_bindgen_futures::spawn_local(async {\n\t\t\twrapper(|wrapper| wrapper.dispatch(FutureMessage::Wake));\n\t\t});\n\t})\n}\n\n/// Blits each rasterized image to a canvas registered on `window.imageCanvases`\npub(crate) fn render_image_data_to_canvases<'a>(image_data: impl IntoIterator<Item = &'a RasterizedImage>) {\n\tlet window = match window() {\n\t\tSome(window) => window,\n\t\tNone => {\n\t\t\terror!(\"Cannot render canvas: window object not found\");\n\t\t\treturn;\n\t\t}\n\t};\n\tlet document = window.document().expect(\"window should have a document\");\n\tlet window_obj = Object::from(window);\n\tlet image_canvases_key = JsValue::from_str(\"imageCanvases\");\n\n\tlet canvases_obj = match Reflect::get(&window_obj, &image_canvases_key) {\n\t\tOk(obj) if !obj.is_undefined() && !obj.is_null() => obj,\n\t\t_ => {\n\t\t\tlet new_obj = Object::new();\n\t\t\tif Reflect::set(&window_obj, &image_canvases_key, &new_obj).is_err() {\n\t\t\t\terror!(\"Failed to create and set imageCanvases object on window\");\n\t\t\t\treturn;\n\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);","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/frontend/wrapper/src/helpers.rs#L117-L153","documentation":"`render_image_data_to_canvases` blits rasterized images onto canvases registered in `window.imageCanvases`. It already handles a missing `window` gracefully, but then calls `window.document()` — a `Option<Document>` — with `.expect(\"window should have a document\")`. In a real browser a window always has a document, so this panic indicates a stubbed `window` object (tests, SSR shims) or an exotic embedding where the global `window` exists without a `document` property.","triggerScenarios":"A `FrontendMessage::UpdateImageData` being emitted while the wrapper runs under a partial DOM mock whose `window` lacks `document` (jsdom configured without a document, custom test doubles, or a compromised/polyfilled global scope).","commonSituations":"Unit tests with hand-rolled `window` stubs; SSR harnesses that define `window` to guard imports but never attach a document; scripts that delete or replace `window.document`.","solutions":["Treat it like the adjacent window check: `let Some(document) = window.document() else { error!(...); return; }`.","In tests, use a complete DOM (jsdom with default url, or a real browser) instead of hand-written `window` doubles.","Avoid loading/initializing the editor before the DOM exists (mount-time dynamic import).","Verify in the host page that `window.document` is present before creating the wrapper."],"exampleFix":"// before\nlet document = window.document().expect(\"window should have a document\");\n\n// after\nlet Some(document) = window.document() else {\n  error!(\"window has no document; cannot blit image canvases\");\n  return;\n};","handlingStrategy":"validation","validationCode":"// TS: probe the DOM before enabling image-canvas previews\nif (typeof window === 'undefined' || !window.document) {\n  console.warn('No window.document; image canvas blitting disabled');\n}","typeGuard":"function hasDocument(): boolean {\n  return typeof window !== 'undefined' && Boolean(window.document);\n}","tryCatchPattern":null,"preventionTips":["Use a complete DOM in tests instead of hand-rolled window stubs.","Mount the editor only after the document exists (post-DOMContentLoaded)."],"tags":["web-sys","document","wasm","panic","dom"],"backgroundTag":"window-document-missing","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}