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
- Retry — the tainted partial was deleted and the next attempt starts over cleanly.
- If reproducible for one host, that host is broken for range downloads — switch to the primary/mirror URL.
- Bypass corporate proxies known to mangle range requests.
- 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
- Always validate the 206 Content-Range offset equals the partial length before appending (this code does — keep it).
- Avoid proxies that reconstitute range responses when downloading large models.
- When a host repeatedly mis-answers ranges, stop resuming against it and switch sources.
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
- server object ends before the expected size (HTTP 416)
- server sent more than the expected
- transfer stalled: no data for
- Complete model file not found
- Download failed from Hugging Face
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)