{"record":{"id":"804920cc3c4f2658","repo":"a-b-street/abstreet","slug":"no-window-title-screen","errorCode":null,"errorMessage":"no window?","messagePattern":"no window\\?","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"map_gui/src/tools/title_screen.rs","lineNumber":241,"sourceCode":"                let err = Command::new(binary).args(args).exec();\n                // We only get here if something broke\n                Transition::Push(PopupMsg::new_state(ctx, \"Error\", vec![err.to_string()]))\n            }\n\n            // On Windows, all we can do is open a new child process. Not sure how to end the\n            // current or detach.\n            #[cfg(windows)]\n            {\n                abstutil::must_run_cmd(Command::new(binary).args(args));\n                Transition::Keep\n            }\n        }\n\n        // On web, leave the current page and go to another.\n        #[cfg(target_arch = \"wasm32\")]\n        {\n            fn set_href(url: &str) -> anyhow::Result<()> {\n                let window = web_sys::window().ok_or(anyhow!(\"no window?\"))?;\n                window.location().set_href(url).map_err(|err| {\n                    anyhow!(err\n                        .as_string()\n                        .unwrap_or(\"window.location.set_href failed\".to_string()))\n                })\n            }\n\n            let page = match self {\n                Executable::ABStreet => \"abstreet\",\n                Executable::FifteenMin => \"fifteen_min\",\n                Executable::OSMViewer => \"osm_viewer\",\n                // This only works on native\n                Executable::ParkingMapper => unreachable!(),\n                Executable::Santa => \"santa\",\n                Executable::RawMapEditor => \"map_editor\",\n                Executable::LTN => \"ltn\",\n            };\n            let url = format!(\"{}.html{}\", page, abstutil::args_to_query_string(args));","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/map_gui/src/tools/title_screen.rs#L223-L259","documentation":"In the title screen's process-replacement logic (map_gui), the wasm-only helper set_href obtains the browser Window via web_sys::window() and errors with anyhow!(\"no window?\") if absent, since navigating requires a real window. It is the same guard as abstutil's parse_args but for navigation.","triggerScenarios":"Clicking a title-screen button on web (replace_process) in an environment where window is unavailable — headless wasm tests, workers, or non-browser runtimes.","commonSituations":"Running the GUI's wasm build in Node or a test harness; web worker without window shim; automation without DOM.","solutions":["Only trigger title-screen navigation from a browser main thread","Provide a window shim or stub in test/worker environments","Skip or mock the navigation step when web_sys::window() returns None"],"exampleFix":"// before\nlet window = web_sys::window().ok_or(anyhow!(\"no window?\"))?;\n// after\nlet Some(window) = web_sys::window() else {\n    log::warn!(\"no window; skipping navigation to {}\", url);\n    return Ok(());\n};","handlingStrategy":"type-guard","validationCode":"if web_sys::window().is_none() {\n    return; // cannot navigate outside a browser\n}","typeGuard":"fn can_navigate() -> bool { web_sys::window().is_some() }","tryCatchPattern":"if let Err(e) = set_href(url) {\n    log::warn!(\"navigation failed: {:?}\", e);\n}","preventionTips":["Trigger title-screen navigation only from user events in a browser","Stub set_href in tests and workers","Gate cfg(wasm32) navigation behind a window availability check"],"tags":["wasm","browser-api","web-sys","navigation"],"backgroundTag":"unsupported-platform","analyzedSha":"0964f29315820c91b171b585eb51e300164e9197","analyzedAt":"2026-09-13T18:02:03.421Z","contentChangedAt":"2026-09-13T18:02:03.421Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}