a-b-street/abstreet · warning · anyhow::Error
window.location.href failed
Error message
window.location.href failed
What it means
After getting the window, update_url calls window.location().href() to read the current URL. This returns a Result in web-sys; on a JS exception it throws this error, falling back to 'window.location.href failed' when the JsValue error has no string form.
Solutions
- Embed the app in a non-sandboxed iframe or add allow-same-origin to the sandbox attribute
- Serve the page over http(s) from a real origin rather than file:/data:/blob:
- Check the browser console for the underlying SecurityError
- Fall back to skipping URL persistence when the origin is opaque
Example fix
// sandboxed iframe causing SecurityError // before <iframe sandbox="allow-scripts" src="app.html"></iframe> // after <iframe sandbox="allow-scripts allow-same-origin" src="app.html"></iframe>
Defensive patterns
Strategy: try-catch
Validate before calling
// opaque-origin check
let origin_ok = window.location().origin().map(|o| !o.is_empty() && o != "null").unwrap_or(false);
if !origin_ok { skip_url_update(); } Try / catch
let url = window.location().href().map_err(|e| anyhow!(e.as_string().unwrap_or_else(|| "window.location.href failed".into())));
if url.is_err() { log::warn!("cannot read location; skipping URL update"); return Ok(()); } Prevention
- Serve the app over http(s) with a real origin; avoid data:/blob:/file: origins
- If embedding in an iframe, include allow-same-origin in the sandbox attribute
- Test in target browsers/embedded webviews early
- Degrade gracefully: treat URL persistence as best-effort
When it happens
Trigger: Reading location.href throws in the browser: unusual security contexts (sandboxed iframe denying navigation/Location access), opaque origins (e.g. sandboxed about:srcdoc frames), or exotic embedded browsers.
Common situations: App embedded in a sandboxed iframe without allow-same-origin, running from a data:/blob: origin, privacy-hardened browsers restricting location access.
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13).
Data as JSON: /api/errors/cb761ac70affbc2a.
Report an issue: GitHub.
Appendix: source
Thrown at widgetry/src/tools/url.rs:110
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| {
anyhow!(err
.as_string()View on GitHub (pinned to 0964f29315)