actix/actix-web · warning · ParseRangeErr
invalid Range header: range starts after end of content
Error message
invalid Range header: range starts after end of content
What it means
Raised by HttpRange::parse (range.rs:50) when the http_range crate returns HttpRangeParseError::NoOverlap: the header parsed successfully but every requested start offset lies beyond the file size. actix-files maps this in NamedFile::into_response (named.rs:609-624) to a 416 Range Not Satisfiable response with 'Content-Range: bytes */<size>'. Syntactically valid, semantically unsatisfiable.
Source
Thrown at actix-files/src/range.rs:30
impl From<http_range::HttpRangeParseError> for HttpRangeParseError {
fn from(err: http_range::HttpRangeParseError) -> Self {
match err {
http_range::HttpRangeParseError::InvalidRange => Self::InvalidRange,
http_range::HttpRangeParseError::NoOverlap => Self::NoOverlap,
}
}
}
#[derive(Debug, Clone, Error)]
#[non_exhaustive]
pub struct ParseRangeErr(#[error(not(source))] HttpRangeParseError);
impl fmt::Display for ParseRangeErr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("invalid Range header: ")?;
f.write_str(match self.0 {
HttpRangeParseError::InvalidRange => "invalid syntax",
HttpRangeParseError::NoOverlap => "range starts after end of content",
})
}
}
/// HTTP Range header representation.
#[derive(Debug, Clone, Copy)]
pub struct HttpRange {
/// Start of range.
pub start: u64,
/// Length of range.
pub length: u64,
}
impl HttpRange {
/// Parses Range HTTP header string as per RFC 2616.
///
/// `header` is HTTP Range header (e.g. `bytes=0-9`).View on GitHub (pinned to 937960ca67)
Solutions
- Have the client re-fetch Content-Length and restart the range request within bounds.
- On the server, ensure the 416 response includes 'Content-Range: bytes */<size>' (actix-files does this automatically) so clients can self-correct.
- For dynamic endpoints, validate the requested range against the actual payload length before responding.
- Check that the file was not truncated or replaced between HEAD and GET.
Example fix
// before: client uses stale size Range: bytes=5000-5999 (file is only 1000 bytes) // after: client clamps to real size or restarts Range: bytes=0-999
Defensive patterns
Strategy: validation
Validate before calling
// Clamp requested ranges to the known content size before issuing the request.
fn clamp_range(start: u64, end: Option<u64>, size: u64) -> Option<(u64, u64)> {
if start >= size { return None } // would trigger NoOverlap
let end = end.map(|e| e.min(size - 1)).unwrap_or(size - 1);
if start > end { return None }
Some((start, end))
} Try / catch
// Same 416 path as syntax errors; actix-files handles it.
match HttpRange::parse(range_header, file_size) {
Ok(ranges) if !ranges.is_empty() => serve(ranges[0]),
_ => respond_416(file_size),
} Prevention
- Re-fetch Content-Length before resuming a range download.
- Detect file replacement (ETag / Last-Modified mismatch) and restart from byte 0.
- Handle 416 in the client by restarting the full download.
When it happens
Trigger: The resource is small but the client asks for a far-later offset, e.g. file is 1000 bytes and the request is 'Range: bytes=5000-' or 'Range: bytes=1500-2000'. Also occurs when a file was truncated/rotated between the client receiving its size and issuing the range request.
Common situations: Resuming a download after the server file was replaced with a shorter one, requesting a byte range computed from a stale Content-Length, or video players seeking past the end of a media file.
Related errors
- invalid Range header: invalid syntax
- No such file
- Provided path has no filename
- Invalid chunk size line: Invalid Size
- Invalid chunk size line: Size is too big
AI-assisted analysis of actix/actix-web@937960ca67 (2026-08-06).
Data as JSON: /data/errors/b9b9afedb9e1a46e.json.
Report an issue: GitHub.