xai-org/grok-build · error

Download failed: HTTP {}

Error message

Download failed: HTTP {}

What it means

download_with_progress downloads an artifact over HTTP after a parallel byte-range attempt fails or is skipped. When the server answers the GET with a non-2xx status, the function bails immediately with the status code rather than writing an error page or empty body to the destination file. This guards the update flow from publishing corrupt artifacts (e.g. 404 HTML pages) as binaries.

Source

Thrown at crates/codegen/xai-grok-update/src/auto_update.rs:1237

/// If the server provides a `Content-Length` header, a determinate bar is shown
/// with bytes downloaded, total size, and ETA. Otherwise a spinner with a byte
/// counter is used as a fallback.
#[doc(hidden)]
pub async fn download_with_progress(url: &str, dest: &std::path::Path) -> Result<()> {
    // Try parallel byte-range first. Falls through to single-connection on any
    // failure (HEAD missing Content-Length, ranges rejected, partial-fetch error).
    match try_parallel_download(url, dest, true).await {
        Ok(()) => return Ok(()),
        Err(e) => {
            tracing::debug!("parallel download failed, falling back to single connection: {e}")
        }
    }

    let client = download_client()?;
    let resp = client.get(url).send().await?;

    if !resp.status().is_success() {
        anyhow::bail!("Download failed: HTTP {}", resp.status());
    }

    let total_size = resp.content_length();

    let pb = if let Some(size) = total_size {
        let pb = ProgressBar::new(size);
        pb.set_style(
            ProgressStyle::default_bar()
                .template("  {bar:30.cyan/dim} {bytes}/{total_bytes} ({eta})")
                .unwrap()
                .progress_chars("━╸─"),
        );
        pb
    } else {
        let pb = ProgressBar::new_spinner();
        pb.set_style(
            ProgressStyle::default_spinner()
                .template("  {spinner:.cyan} {bytes} downloaded")

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Verify the URL is correct and the release/asset exists for the requested tag (check the repo's releases or GCS bucket).
  2. Re-run after a short delay if the status is 429 or 5xx; respect any Retry-After header.
  3. If 403, check credentials/expiry of the token used (e.g. GITHUB_TOKEN) and repo/bucket access permissions.
  4. Check network/proxy configuration; a captive portal or proxy can turn the GET into an error response.
  5. As a last resort clear any cached version metadata so the updater recomputes a valid download URL.

Example fix

// before: blind call with a stale URL
let url = format!("https://example.com/dist/{old_tag}/cli");
download_with_progress(&url, &dest).await?;

// after: pre-check the URL / pin to a live channel metadata URL
let meta: ChannelMetadata = reqwest::get(&channel_url).await?.json().await?;
let url = meta.latest_binary_url;
download_with_progress(&url, &dest).await?;
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check the URL resolves to a 2xx before invoking the downloader
let client = reqwest::Client::new();
let status = client.head(url).send().await?.status();
if !status.is_success() {
    anyhow::bail!("refusing to download {url}: HTTP {status}");
}

Type guard

fn is_downloadable(resp: &reqwest::Response) -> bool {
    resp.status().is_success()
}

Try / catch

match download_with_progress(url, &dest).await {
    Ok(()) => println!("updated"),
    Err(e) if e.to_string().contains("HTTP 429") || e.to_string().contains("HTTP 5") => {
        // exponential backoff retry
        tokio::time::sleep(Duration::from_secs(5)).await;
        download_with_progress(url, &dest).await?;
    }
    Err(e) => eprintln!("download failed: {e}"), // surface status code to user
}

Prevention

When it happens

Trigger: Calling download_with_progress(url, dest) where the HTTP GET returns a non-success status: 404 (artifact/tag missing), 403 (rate-limited or no access to GCS/GitHub release asset), 401, 429, 5xx server errors, or 3xx that the client does not follow to a 2xx.

Common situations: A release tag was renamed or deleted so the asset URL 404s; a private repo bucket returns 403 because GITHUB_TOKEN is missing/expired; GitHub API rate limiting (429) after many checks; a transient 502/503 from a CDN during a release rollout; a typo'd or outdated version URL.

Related errors


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/2bc1c04a1b08b809. Report an issue: GitHub.