zed-industries/zed · error · anyhow::Error
status error {}, response: {text:?}
Error message
status error {}, response: {text:?} What it means
The GitHub release lister (latest_github_release) reads the full response body for GET /repos/{repo}/releases and bails on any 4xx status, embedding the numeric code and response text. 401 means bad credentials, 403 almost always means unauthenticated rate limit (60 req/h per IP) or a blocked token, and 404 means the owner/repo or the releases endpoint is wrong/private.
Source
Thrown at crates/http_client/src/github.rs:59
let url = format!("{GITHUB_API_URL}/repos/{repo_name_with_owner}/releases");
let request = github_api_request(&url)?;
let mut response = http
.send(request)
.await
.context("error fetching latest release")?;
let mut body = Vec::new();
response
.body_mut()
.read_to_end(&mut body)
.await
.context("error reading latest release")?;
if response.status().is_client_error() {
let text = String::from_utf8_lossy(body.as_slice());
bail!(
"status error {}, response: {text:?}",
response.status().as_u16()
);
}
let releases = match serde_json::from_slice::<Vec<GithubRelease>>(body.as_slice()) {
Ok(releases) => releases,
Err(err) => {
log::error!("Error deserializing: {err:?}");
log::error!(
"GitHub API response text: {:?}",
String::from_utf8_lossy(body.as_slice())
);
anyhow::bail!("error deserializing latest release: {err:?}");
}
};
View on GitHub (pinned to f4178619ac)
Solutions
- Check the embedded status: 403 → wait for the rate-limit reset or set a valid GITHUB_TOKEN; 404 → verify owner/repo spelling and visibility; 401 → refresh the token
- Query GET /rate_limit to see remaining/reset before retrying
- Cache the latest-release result instead of calling the API on every startup
- Read the response text in the error message — GitHub states the exact reason (rate limit reset time, bad credentials)
Defensive patterns
Strategy: retry
Validate before calling
// preflight the shared anonymous rate limit before hammering /releases
let rl: serde_json::Value = serde_json::from_slice(
&http.get("https://api.github.com/rate_limit", Default::default(), true).await?.body_mut().bytes().await?,
)?;
if rl["resources"]["core"]["remaining"].as_i64() == Some(0) {
anyhow::bail!("rate limit exhausted, resets at epoch {}", rl["resources"]["core"]["reset"]);
} Try / catch
match latest_github_release(...).await {
Ok(r) => Ok(r),
Err(e) if e.to_string().contains("status error 403") => retry_after_reset().await,
Err(e) if e.to_string().contains("status error 404") => Err(anyhow!("repo/release does not exist")),
Err(e) => Err(e),
} Prevention
- Always attach a token to GitHub API requests (60/h anonymous vs 5000/h authenticated)
- Cache release metadata so startup does not re-fetch every run
- Parse the numeric status out of the message and branch: 401 token, 403 rate limit, 404 wrong repo
When it happens
Trigger: Calling latest_github_release with a repo name that does not exist (typo, renamed repo, private without auth), without a GITHUB_TOKEN on a machine sharing a NATed IP that exhausted the 60 req/h anonymous limit, or with an expired/insufficient-scope token.
Common situations: Dev machines behind corporate NAT hitting the shared rate limit; CI jobs fetching extension/LSP binaries repeatedly; repos renamed or transferred so the old URL 404s; tokens revoked by GitHub.
Related errors
- could not locate run '{run_id}' in the local run index ({run
- Failed to connect to API: {} {}
- Failed to connect to API: {} {}
- Failed to connect to DeepSeek API: {} {}
- error deserializing latest release: {err:?}
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/2258d96115e5df78.
Report an issue: GitHub.