ducaale/xh · error
Invalid Content-Range
Error message
Invalid Content-Range: {:?} What it means
After parsing first_byte_pos, last_byte_pos and optional complete_length out of Content-Range, the tool validates them. This error fires when the header is internally inconsistent: the last byte position precedes the first (first_byte_pos > last_byte_pos), or a supplied complete_length is not greater than last_byte_pos.
Solutions
- Delete the partially downloaded file and restart the download from byte 0
- Verify the server's Content-Range arithmetic with a manual ranged request (curl -r) and fix/upgrade the server if inconsistent
- Disable resume/partial downloads for this host if it's known to emit broken ranges
Defensive patterns
Strategy: try-catch
Validate before calling
fn content_range_sane(first: u64, last: u64, total: Option<u64>) -> bool {
first <= last && total.map_or(true, |t| last < t)
} Try / catch
match total_for_content_range(header, expected_start) {
Ok(total) => resume_from(expected_start, total),
Err(e) if e.to_string().contains("Invalid Content-Range") => {
eprintln!("Server sent inconsistent Content-Range; restarting from scratch");
delete_partial_and_restart();
}
Err(e) => return Err(e),
} Prevention
- Delete the partial file instead of resuming when the server misbehaves
- Verify ranged requests manually with curl -r before scripting resumes
- Watch for server-side file changes between initial and resume requests
When it happens
Trigger: Server sends e.g. 'bytes 500-100/1000' where 100 < 500, or 'bytes 0-999/500' where complete_length (500) <= last_byte_pos (999).
Common situations: Buggy download servers computing range arithmetic wrong, caching layers serving mismatched partial content, resume offset out of sync with the file size on the server.
Related errors
- Content-Range has wrong end
- Can't parse Content-Range header, can't resume download
- Content-Range has wrong start
- message-signature: Duplicate covered component identifier
- unknown compression type
AI-assisted analysis of ducaale/xh@2404aceecc (2026-09-13).
Data as JSON: /api/errors/81996711dfc44daf.
Report an issue: GitHub.
Appendix: source
Thrown at src/download.rs:143
.context("Can't parse Content-Range first_byte_pos")?;
let last_byte_pos: u64 = caps
.name("last_byte_pos")
.unwrap()
.as_str()
.parse()
.context("Can't parse Content-Range last_byte_pos")?;
let complete_length: Option<u64> = caps
.name("complete_length")
.map(|num| {
num.as_str()
.parse()
.context("Can't parse Content-Range complete_length")
})
.transpose()?;
// Note that last_byte_pos must be strictly less than complete_length
// If first_byte_pos == last_byte_pos exactly one byte is sent
if first_byte_pos > last_byte_pos {
return Err(anyhow!("Invalid Content-Range: {:?}", header));
}
if let Some(complete_length) = complete_length {
if last_byte_pos >= complete_length {
return Err(anyhow!("Invalid Content-Range: {:?}", header));
}
if complete_length != last_byte_pos + 1 {
return Err(anyhow!("Content-Range has wrong end: {:?}", header));
}
}
if expected_start != first_byte_pos {
return Err(anyhow!("Content-Range has wrong start: {:?}", header));
}
Ok(last_byte_pos + 1)
}
const BAR_TEMPLATE: &str =
"{spinner:.green} {percent}% [{wide_bar:.cyan/blue}] {bytes} {bytes_per_sec} ETA {eta}";
const UNCOLORED_BAR_TEMPLATE: &str =View on GitHub (pinned to 2404aceecc)