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

window.location.href failed

Error message

window.location.href failed

What it means

After obtaining the window, parse_args calls window.location().href(), which returns a Result whose Err case is a JsValue. The code converts the JsValue to a String; if it is not a string (or is empty) it falls back to the literal message "window.location.href failed". This wraps a JS-side failure of the href property access into an anyhow error.

Solutions

  1. Log the raw JsValue in the browser console to see the underlying JS error
  2. Verify the page origin allows reading location.href (avoid exotic sandbox attributes)
  3. Consider wrapping with js_sys::Error to extract a better message than the fallback string
  4. Fall back to window.location.search which is less likely to fail if only the query string is needed

Example fix

// before
anyhow!(err.as_string().unwrap_or("window.location.href failed".to_string()))
// after
let msg = err.as_string().unwrap_or_else(|| format!("window.location.href failed: {:?}", err));
Err(anyhow!(msg))
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure location is readable
let ok = web_sys::window().map(|w| !w.location().href().is_err()).unwrap_or(false);

Try / catch

match cli_args() {
    Ok(args) => use(args),
    Err(e) => {
        log::error!("failed to read URL args: {:?}", e);
        default_args()
    }
}

Prevention

When it happens

Trigger: Calling cli_args() in a browser when reading location.href throws or returns a rejected JsValue — rare, but possible if the document origin/context is detached (e.g. window closed, about:blank in some sandboxed iframes, or the JsValue error is not a string).

Common situations: Sandboxed iframes with restricted navigation APIs; running inside a partially torn-down page; embedding the app in an environment where Location access is blocked by the host page.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at abstutil/src/cli.rs:50

    // 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)