Hmbown/CodeWhale · error

failed to download

Error message

failed to download {url}

What it means

The CLI self-updater downloads the new release binary from `url` with retries; this is the terminal error returned once every retry attempt has failed. The final message is the generic fallback `anyhow!("failed to download {url}")` used only when the retry loop exhausts without a concrete recorded error, though normally `last_error` carries the real transport error from the last attempt.

Solutions

  1. Check basic network reachability of the download URL (curl the URL shown in the message).
  2. Verify proxy settings (HTTP_PROXY/HTTPS_PROXY or the `proxy` config) — a bad proxy fails every retry.
  3. Increase or clear the download timeout configuration and retry the update.
  4. As a fallback, download and install the release manually from the project's releases page.

Example fix

// before: update fails behind proxy
$ codewhale update
// after: export working proxy, retry
$ export HTTPS_PROXY=http://proxy.corp:8080
$ codewhale update
Defensive patterns

Strategy: retry

Validate before calling

import std.net;
// pre-check reachability before invoking the updater
let host = url.host_str().ok_or("no host")?;
std::net::TcpStream::connect((host, 443)).map_err(|e| format!("unreachable: {e}"))?;

Try / catch

match cli.update() {
    Err(e) if e.to_string().contains("failed to download") => {
        eprintln!("network issue, falling back to manual install: {e}");
        print_manual_install_instructions();
    }
    Err(e) => return Err(e),
    Ok(()) => {}
}

Prevention

When it happens

Trigger: Calling the CLI update check/install path when `download_url_once` returns `Err` on every attempt (network outage, proxy failure, timeout, HTTP error) until the retry budget is exhausted.

Common situations: Corporate proxy misconfiguration, DNS failures, GitHub releases unreachable or rate-limited, or an overly short download timeout on a slow connection.

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 Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/335e9bbd1d0976bf. Report an issue: GitHub.

Appendix: source

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

            Ok((status, bytes)) if status.is_success() => return Ok(bytes),
            Ok((status, bytes)) => {
                let body = String::from_utf8_lossy(&bytes);
                let error = anyhow!("download failed with HTTP {status}: {body}");
                if should_retry_http_status(status) && attempt < UPDATE_HTTP_ATTEMPTS {
                    last_error = Some(error);
                    sleep_before_update_retry(attempt);
                    continue;
                }
                return Err(error);
            }
            Err(error) if attempt < UPDATE_HTTP_ATTEMPTS => {
                last_error = Some(error);
                sleep_before_update_retry(attempt);
            }
            Err(error) => return Err(error),
        }
    }
    Err(last_error.unwrap_or_else(|| anyhow!("failed to download {url}")))
}

fn download_url_once(
    url: &str,
    proxy: Option<&Proxy>,
    timeout: Duration,
) -> Result<(reqwest::StatusCode, Vec<u8>)> {
    let client = update_http_client_with_timeout(proxy, timeout)?;
    let response = client
        .get(url)
        .send()
        .with_context(|| format!("failed to download {url}"))?;
    let status = response.status();
    let bytes = response
        .bytes()
        .with_context(|| format!("failed to read response body from {url}"))?;

    Ok((status, bytes.to_vec()))

View on GitHub (pinned to 73e0f67d83)