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

  1. 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
  2. Query GET /rate_limit to see remaining/reset before retrying
  3. Cache the latest-release result instead of calling the API on every startup
  4. 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

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


AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20). Data as JSON: /api/errors/2258d96115e5df78. Report an issue: GitHub.