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

no window?

Error message

no window?

What it means

In the wasm32 build of abstutil's CLI argument parsing, parse_args first needs the browser's global Window object via web_sys::window(). If that returns None there is no JS global scope to read the URL query string from, so the function aborts with anyhow!("no window?"). This guards code that must only ever run inside a browser.

Solutions

  1. Ensure the code runs in a real browser main thread where window exists
  2. For non-browser wasm environments, add a JS shim that defines a global window object before the module loads
  3. Restructure to pass CLI args explicitly instead of reading window.location.href
  4. Use #[cfg] to gate browser-only code paths and provide a non-wasm fallback

Example fix

// before
let window = web_sys::window().ok_or(anyhow!("no window?"))?;
// after
let Some(window) = web_sys::window() else {
    return Ok(std::env::args().skip(1).collect()); // non-browser fallback
};
Defensive patterns

Strategy: fallback

Validate before calling

// before calling wasm-only arg parsing
if web_sys::window().is_none() {
    // non-browser environment: skip or use env::args
}

Type guard

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

Try / catch

match cli_args() {
    Ok(args) => use(args),
    Err(e) if e.to_string().contains("no window?") => fallback_args(),
    Err(e) => report(e),
}

Prevention

When it happens

Trigger: Calling cli_args() (wasm32 target) from a WebAssembly context that is not a browser main thread with a DOM window — e.g. running in Node/wasmtime, a web worker without window shim, or before JS glue sets up globals.

Common situations: Testing wasm code headlessly in Node; running wasm tests outside a browser; embedding the wasm module in a worker; calling parse_args during non-DOM initialization.

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/6c9c10622b5417b8. Report an issue: GitHub.

Appendix: source

Thrown at abstutil/src/cli.rs:48

/// between arguments. The string returned starts with `?`, unless the arguments are all empty.
pub fn args_to_query_string(args: Vec<String>) -> String {
    // TODO Similar to parse_args forgoing a URL decoding crate, just handle this one
    // transformation
    let result = args
        .into_iter()
        .map(|x| x.replace(" ", "%20"))
        .collect::<Vec<_>>()
        .join("&");
    if result.is_empty() {
        result
    } else {
        format!("?{}", result)
    }
}

#[cfg(target_arch = "wasm32")]
fn parse_args() -> anyhow::Result<Vec<String>> {
    let window = web_sys::window().ok_or(anyhow!("no window?"))?;
    let url = window.location().href().map_err(|err| {
        anyhow!(err
            .as_string()
            .unwrap_or("window.location.href failed".to_string()))
    })?;
    // Consider using a proper url parsing crate. This works fine for now, though.
    let url_parts = url.split("?").collect::<Vec<_>>();
    if url_parts.len() != 2 {
        bail!("URL {url} doesn't seem to have query params");
    }
    let parts = url_parts[1]
        .split("&")
        .map(|x| x.replace("%20", " ").to_string())
        .collect::<Vec<_>>();
    Ok(parts)
}

View on GitHub (pinned to 0964f29315)