xai-org/grok-build · error

response missing Content-Length

Error message

response missing Content-Length

What it means

try_parallel_download first issues a HEAD request to learn the file size and validate that parallel range downloads are worthwhile. If the successful HEAD response carries no Content-Length header, the size is unknown and this error is thrown because chunked range downloads cannot be planned without it.

Source

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

/// Try a parallel byte-range download to `dest`. Returns Err if the server
/// doesn't advertise a Content-Length, the file is too small to be worth
/// splitting, the range request is rejected, or any chunk transfer fails.
/// The caller is expected to fall back to a single-connection download on Err.
async fn try_parallel_download(
    url: &str,
    dest: &std::path::Path,
    with_progress: bool,
) -> Result<()> {
    let client = download_client()?;

    let head = client.head(url).send().await?;
    if !head.status().is_success() {
        anyhow::bail!("HEAD failed: HTTP {}", head.status());
    }
    let size = head
        .content_length()
        .ok_or_else(|| anyhow::anyhow!("response missing Content-Length"))?;
    if size < PARALLEL_DOWNLOAD_MIN_BYTES {
        anyhow::bail!("file too small for parallel download ({} bytes)", size);
    }

    let n_chunks = parallel_chunk_count(size);
    if n_chunks < 2 {
        anyhow::bail!(
            "file size yields {} chunk(s); not worth parallelizing",
            n_chunks
        );
    }
    let chunk_size = size.div_ceil(n_chunks);

    let pb = if with_progress {
        let pb = ProgressBar::new(size);
        pb.set_style(
            ProgressStyle::default_bar()
                .template("  {bar:30.cyan/dim} {bytes}/{total_bytes} ({eta})")

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Fall back to the non-parallel single-stream download path when Content-Length is missing
  2. Verify with `curl -I <url>` whether the server returns Content-Length on HEAD
  3. Bypass or reconfigure the proxy/CDN that is stripping the header
  4. Point the download at the canonical artifact URL/mirror that serves proper HEAD metadata

Example fix

// before
let size = head.content_length()
    .ok_or_else(|| anyhow::anyhow!("response missing Content-Length"))?;
// after
match head.content_length() {
    Some(size) if size >= PARALLEL_DOWNLOAD_MIN_BYTES => download_parallel(url, size).await,
    _ => download_single_stream(url).await, // graceful fallback
}
Defensive patterns

Strategy: fallback

Validate before calling

let head = client.head(url).send().await?;
let has_len = head.content_length().is_some();
if !has_len { eprintln!("server omitted Content-Length; use single-stream download"); }

Type guard

fn supports_parallel_download(head: &reqwest::Response) -> bool {
    head.status().is_success() && head.content_length().map_or(false, |n| n >= PARALLEL_DOWNLOAD_MIN_BYTES)
}

Try / catch

match download_with_progress(url, &dest).await {
    Err(e) if e.to_string().contains("response missing Content-Length") => {
        download_single_stream(url, &dest).await?; // fallback
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling download_with_progress / download_silent against a server whose HEAD response for the artifact URL omits Content-Length — e.g. chunked transfer encoding, compression middleware, or a CDN rewriting HEAD responses.

Common situations: Downloading through a reverse proxy or CDN that strips/omits Content-Length on HEAD; servers that respond 200 with chunked encoding instead of a length; enterprise proxies that transform responses; misconfigured artifact mirror.

Related errors


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