a-b-street/abstreet · error · anyhow::Error
HTTP
Error message
HTTP {}: {} What it means
FileLoader fetches a remote file over HTTP in the browser and sends the downloaded bytes over a channel. When the fetch response's status is not OK (resp.ok() false), it formats 'HTTP <status>: <status_text>' and sends that as the error. It surfaces any non-2xx HTTP response from the server hosting the file.
Solutions
- Verify the URL is correct and the file is reachable (curl -I the URL)
- Check server logs for the status code's cause
- Fix CORS headers (Access-Control-Allow-Origin) if the browser is blocking the response
- Serve the file from the correct location or redeploy the asset
Example fix
// before let url = "data/scenarios/map.bin"; // after: full, verified URL let url = "https://example.com/abst/data/scenarios/map.bin";
Defensive patterns
Strategy: validation
Validate before calling
// before loading, verify reachability and permissions
let resp = reqwest::blocking::head(url).send()?;
if !resp.status().is_success() {
bail!("asset {} not available: {}", url, resp.status());
} Type guard
function is_ok_response(resp: Response): boolean { return resp.ok; } Try / catch
match file_loader.response.recv() {
Ok(Ok(bytes)) => use(bytes),
Ok(Err(e)) => show_error(format!("Could not load file: {} — check the URL and server", e)),
Err(_) => show_error("loader channel closed"),
} Prevention
- Verify asset URLs with curl -I before deploying
- Deploy all data files alongside the app and keep paths consistent
- Configure CORS headers on the asset server
- Monitor server logs for 404/403 on asset requests
When it happens
Trigger: Calling the load/new_state API with a URL that the server answers with a non-2xx status: 404 for a missing file, 403 for permissions, 500 for a server error, CORS-related 4xx, or a redirect that ends in an error page.
Common situations: Wrong or misspelled URL/path for the data file, file not deployed to the web server, missing CORS headers causing the browser to reject the response, server misconfiguration.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13).
Data as JSON: /api/errors/54da5c611554005b.
Report an issue: GitHub.
Appendix: source
Thrown at widgetry/src/tools/load.rs:191
let raw_body = resp.body().unwrap_throw();
let body = ReadableStream::from_raw(raw_body.dyn_into().unwrap_throw());
let mut stream = body.into_stream();
let mut buffer = Vec::new();
while let Some(Ok(chunk)) = stream.next().await {
let array = js_sys::Uint8Array::new(&chunk);
if let Err(err) =
tx_read_bytes.try_send(array.byte_length() as usize)
{
warn!("Couldn't send update on bytes: {}", err);
}
// TODO Can we avoid this clone?
buffer.extend(array.to_vec());
}
tx.send(Ok(buffer)).unwrap();
} else {
let status = resp.status();
let err = resp.status_text();
tx.send(Err(anyhow!("HTTP {}: {}", status, err))).unwrap();
}
}
Err(err) => {
tx.send(Err(anyhow!("{:?}", err))).unwrap();
}
}
});
Box::new(FileLoader {
response: rx,
on_load: Some(on_load),
panel: ctx.make_loading_screen(Text::from(format!("Loading {}...", url))),
started: Instant::now(),
url,
total_bytes: None,
read_bytes: 0,
got_total_bytes,
got_read_bytes,View on GitHub (pinned to 0964f29315)