cjpais/Handy · error · anyhow::Error

server returned Content-Range starting at

Error message

server returned Content-Range starting at {:?}, expected {}

What it means

Raised on a 206 Partial Content reply whose Content-Range start offset does not exactly equal the end of the local partial file. Appending such a body would silently corrupt the model (bytes skipped or duplicated), so the partial is deleted and the error returned. This is a server-misbehavior guard: a correct server must echo the exact 'bytes=N-' offset that was requested.

Solutions

  1. Retry — the tainted partial was deleted and the next attempt starts over cleanly.
  2. If reproducible for one host, that host is broken for range downloads — switch to the primary/mirror URL.
  3. Bypass corporate proxies known to mangle range requests.
  4. Report the URL if the official catalog entry consistently triggers it.
Defensive patterns

Strategy: retry

Try / catch

match manager.download_model(model_id, None).await {
    Ok(_) => Ok(()),
    Err(e) if e.to_string().contains("Content-Range starting at") => {
        // tainted partial already deleted; clean restart is the only safe move
        manager.download_model(model_id, None).await
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Server responds 206 but with a Content-Range starting at 0 (ignoring the Range while claiming partial), a missing/unparseable Content-Range header on a 206, or a proxy rewriting range responses.

Common situations: Misconfigured CDNs or object stores that ack Range but return full bodies; middleboxes/proxies that reconstitute responses and drop Content-Range; exotic servers that clamp ranges differently.

Related errors


AI-assisted analysis of cjpais/Handy@c89b7bf389 (2026-08-17). Data as JSON: /api/errors/88cecbb212f6cdb8. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/src/managers/model/download.rs:274

            resume_from = 0;
        }
        if !response.status().is_success() {
            return Err(anyhow::anyhow!(
                "server returned HTTP {}",
                response.status()
            ));
        }
        // On a 206, trust but verify the offset: a reply starting anywhere but
        // exactly our partial's end would silently corrupt the file on append.
        if resume_from > 0 && response.status() == reqwest::StatusCode::PARTIAL_CONTENT {
            let starts_at = response
                .headers()
                .get(reqwest::header::CONTENT_RANGE)
                .and_then(|v| v.to_str().ok())
                .and_then(content_range_start);
            if starts_at != Some(resume_from) {
                let _ = fs::remove_file(partial_path);
                return Err(anyhow::anyhow!(
                    "server returned Content-Range starting at {:?}, expected {}",
                    starts_at,
                    resume_from
                ));
            }
        }
        // When the catalog pins the size, a server advertising a different
        // total is already misbehaving — reject before writing anything.
        if let (Some(expected), Some(len)) = (expected_size, response.content_length()) {
            if resume_from + len != expected {
                return Err(anyhow::anyhow!(
                    "server advertises {} bytes, expected {}",
                    resume_from + len,
                    expected
                ));
            }
        }

View on GitHub (pinned to c89b7bf389)