Hmbown/CodeWhale · error · anyhow::Error

failed to fetch release redirect from {url}: HTTP {status} {

Error message

failed to fetch release redirect from {url}: HTTP {status}
{body}

What it means

The HTTP request that resolves the latest release tag returned a non-2xx status. The full status code and response body are embedded in the error, so the upstream failure (rate limit, missing repo, auth demand) is visible directly in the message.

Source

Thrown at crates/cli/src/update.rs:1439

    let status = response.status();
    let final_url = response.url().clone();
    if status.is_success() {
        if let Some(tag_name) = release_tag_from_github_release_url(&final_url) {
            return Ok(tag_name);
        }
        let body = response
            .text()
            .with_context(|| format!("failed to read release redirect response from {url}"))?;
        if let Some(tag_name) = release_tag_from_github_release_html(&body) {
            return Ok(tag_name);
        }
        bail!("release redirect did not resolve to a tag URL: {final_url}");
    }

    let body = response
        .text()
        .with_context(|| format!("failed to read release redirect response from {url}"))?;
    bail!("failed to fetch release redirect from {url}: HTTP {status}\n{body}");
}

fn release_tag_from_github_release_url(url: &reqwest::Url) -> Option<String> {
    let segments = url.path_segments()?.collect::<Vec<_>>();
    segments
        .windows(3)
        .find(|window| window[0] == "releases" && window[1] == "tag")
        .map(|window| window[2].to_string())
        .filter(|tag| !tag.is_empty())
}

fn release_tag_from_github_release_html(body: &str) -> Option<String> {
    const MARKERS: &[&str] = &[
        "/Hmbown/CodeWhale/releases/tag/",
        "/hmbown/CodeWhale/releases/tag/",
        "/releases/tag/",
    ];
    for marker in MARKERS {

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Read the embedded HTTP status/body: 429/403 means rate limiting — wait or supply GitHub credentials/token if the updater supports it
  2. Verify the repository/release still exists and the URL is correct (404)
  3. Retry after a short wait for 5xx/transient failures
  4. Update to an explicitly pinned version that skips latest-tag resolution, or install from source with `cargo install codewhale-cli --locked`

Example fix

# before
$ codewhale update
failed to fetch release redirect ...: HTTP 429

# after
$ sleep 300 && codewhale update   # or set GITHUB token / pin an explicit version
Defensive patterns

Strategy: retry

Validate before calling

// Check reachability and status before invoking the updater:
let resp = reqwest::blocking::get(latest_url)?;
match resp.status() {
    s if s.is_success() => { /* safe to proceed */ }
    reqwest::StatusCode::TOO_MANY_REQUESTS => { /* wait and retry later */ }
    s => { /* abort with clear message; body already known */ }
}

Try / catch

match fetch_release_tag(&url) {
    Ok(tag) => Ok(tag),
    Err(e) => {
        let msg = e.to_string();
        if msg.contains("HTTP 429") || msg.contains("HTTP 403") {
            // rate limited: schedule retry, do not hammer
            schedule_retry(Duration::from_secs(300))
        } else if msg.contains("HTTP 404") {
            // repo/release gone: stop retrying, report
            Err(e.context("release source unavailable"))
        } else { Err(e) }
    }
}

Prevention

When it happens

Trigger: GET on the releases/latest redirect URL fails with e.g. 404 (repository or release renamed/removed), 429 (GitHub unauthenticated rate limiting), 403 (rate-limit block or region restriction), or 5xx — the response body is read and appended as 'HTTP {status}\n{body}'.

Common situations: Heavy unauthenticated GitHub API/web usage from one IP hitting rate limits; GITHUB_TOKEN not set for the update; the repository was renamed, made private, or transferred; GitHub outage or maintenance window.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/5e3cdb815bb3ca33. Report an issue: GitHub.