a-b-street/abstreet · error · anyhow::Error

no window?

Error message

no window?

What it means

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.

Solutions

  1. Only trigger title-screen navigation from a browser main thread
  2. Provide a window shim or stub in test/worker environments
  3. Skip or mock the navigation step when web_sys::window() returns None

Example fix

// before
let window = web_sys::window().ok_or(anyhow!("no window?"))?;
// after
let Some(window) = web_sys::window() else {
    log::warn!("no window; skipping navigation to {}", url);
    return Ok(());
};
Defensive patterns

Strategy: type-guard

Validate before calling

if web_sys::window().is_none() {
    return; // cannot navigate outside a browser
}

Type guard

fn can_navigate() -> bool { web_sys::window().is_some() }

Try / catch

if let Err(e) = set_href(url) {
    log::warn!("navigation failed: {:?}", e);
}

Prevention

When it happens

Trigger: Clicking a title-screen button on web (replace_process) in an environment where window is unavailable — headless wasm tests, workers, or non-browser runtimes.

Common situations: Running the GUI's wasm build in Node or a test harness; web worker without window shim; automation without DOM.

Understand the failure class

Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.

Related errors


AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13). Data as JSON: /api/errors/804920cc3c4f2658. Report an issue: GitHub.

Appendix: source

Thrown at map_gui/src/tools/title_screen.rs:241

                let err = Command::new(binary).args(args).exec();
                // We only get here if something broke
                Transition::Push(PopupMsg::new_state(ctx, "Error", vec![err.to_string()]))
            }

            // On Windows, all we can do is open a new child process. Not sure how to end the
            // current or detach.
            #[cfg(windows)]
            {
                abstutil::must_run_cmd(Command::new(binary).args(args));
                Transition::Keep
            }
        }

        // On web, leave the current page and go to another.
        #[cfg(target_arch = "wasm32")]
        {
            fn set_href(url: &str) -> anyhow::Result<()> {
                let window = web_sys::window().ok_or(anyhow!("no window?"))?;
                window.location().set_href(url).map_err(|err| {
                    anyhow!(err
                        .as_string()
                        .unwrap_or("window.location.set_href failed".to_string()))
                })
            }

            let page = match self {
                Executable::ABStreet => "abstreet",
                Executable::FifteenMin => "fifteen_min",
                Executable::OSMViewer => "osm_viewer",
                // This only works on native
                Executable::ParkingMapper => unreachable!(),
                Executable::Santa => "santa",
                Executable::RawMapEditor => "map_editor",
                Executable::LTN => "ltn",
            };
            let url = format!("{}.html{}", page, abstutil::args_to_query_string(args));

View on GitHub (pinned to 0964f29315)