a-b-street/abstreet · warning · anyhow::Error
no window?
Error message
no window?
What it means
update_url reads window.location.href to rewrite the page URL; in wasm it needs the global Window object. web_sys::window() returned None, so the library throws 'no window?'. web_sys::window() is only Some in a browser main-thread context.
Solutions
- Only call must_update_url from the browser main thread with a real DOM
- Guard the call with a web_sys::window().is_some() check and skip URL updates otherwise
- Skip URL persistence in tests/workers — the function is already #[allow(unused_variables)] for non-wasm targets
Example fix
// before
must_update_url(ctx, |url| ...);
// after
if web_sys::window().is_some() {
must_update_url(ctx, |url| ...);
} Defensive patterns
Strategy: type-guard
Validate before calling
if web_sys::window().is_none() {
log::warn!("no browser window; skipping URL update");
return;
} Type guard
fn has_window() -> bool { web_sys::window().is_some() } Try / catch
if let Err(e) = update_url(transform) {
log::warn!("URL update skipped: {:?}", e);
} Prevention
- Only call URL-updating APIs from the browser main thread
- Skip URL persistence in wasm tests and workers
- Gate must_update_url behind a web_sys::window().is_some() check
When it happens
Trigger: Calling must_update_url/update_url outside a browser window context: on a non-main thread, in a worker, in Node/tests targeting wasm32, or in headless wasm runtimes without DOM.
Common situations: Unit tests running under wasm-bindgen-test without DOM, code executing in a Web Worker, calling URL updating during early init before the DOM is ready.
Related errors
AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13).
Data as JSON: /api/errors/4d8d37a76fc31979.
Report an issue: GitHub.
Appendix: source
Thrown at widgetry/src/tools/url.rs:108
// But actually, the algebra shows we don't even need window_width. Easy!
let cam_zoom = 1.0 / horiz_meters_per_pixel;
Some((pt, cam_zoom))
}
}
fn must_update_url(transform: Box<dyn Fn(String) -> String>) {
if let Err(err) = update_url(transform) {
warn!("Couldn't update URL: {}", err);
}
}
#[allow(unused_variables)]
fn update_url(transform: Box<dyn Fn(String) -> String>) -> Result<()> {
#[cfg(target_arch = "wasm32")]
{
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()))
})?;
let new_url = (transform)(url);
// Setting window.location.href may seem like the obvious thing to do, but that actually
// refreshes the page. This method just changes the URL and doesn't mess up history. See
// https://developer.mozilla.org/en-US/docs/Web/API/History_API/Working_with_the_History_API.
let history = window.history().map_err(|err| {
anyhow!(err
.as_string()
.unwrap_or("window.history failed".to_string()))
})?;
history
.replace_state_with_url(&wasm_bindgen::JsValue::NULL, "", Some(&new_url))
.map_err(|err| {View on GitHub (pinned to 0964f29315)