actix/actix-web · warning · ParseRangeErr
invalid Range header: invalid syntax
Error message
invalid Range header: invalid syntax
What it means
Raised by HttpRange::parse (range.rs:50) when the underlying http_range crate returns HttpRangeParseError::InvalidRange, meaning the Range header bytes do not conform to the bytes-ranges grammar from RFC 7233. actix-files surfaces it as ParseRangeErr and, in NamedFile::into_response (named.rs:609-624), converts a failed parse into a 416 Range Not Satisfiable response with a Content-Range of 'bytes */<size>'. It is therefore a client-side protocol error, not a server bug.
Source
Thrown at actix-files/src/range.rs:29
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.
///View on GitHub (pinned to 937960ca67)
Solutions
- Verify the client sends a syntactically valid 'bytes=' range such as 'Range: bytes=0-499' or 'Range: bytes=-500'.
- If you control the client, build the header with a tested helper rather than string concatenation.
- If the header is genuinely untrusted, the 416 actix returns is correct; no server change is needed.
- Log the raw Range header value server-side to identify which client is misbehaving.
Example fix
// before (malformed) curl -H "Range: 0-99" http://host/file // after (valid) curl -H "Range: bytes=0-99" http://host/file
Defensive patterns
Strategy: validation
Validate before calling
// Validate the Range header string shape before relying on it.
fn valid_range_syntax(h: &str) -> bool {
let h = h.trim();
let Some(rest) = h.strip_prefix("bytes=") else { return false };
if rest.is_empty() { return false }
rest.split(',').all(|spec| {
let spec = spec.trim();
if spec.is_empty() { return false }
let (a, b) = spec.split_once('-').unwrap_or((spec, ""));
(a.is_empty() || a.chars().all(|c| c.is_ascii_digit()))
&& (b.is_empty() || b.chars().all(|c| c.is_ascii_digit()))
})
} Try / catch
// actix-files already converts this to 416; only handle if parsing manually.
match HttpRange::parse(range_header, file_size) {
Ok(ranges) => { /* serve first range */ }
Err(_) => {
return HttpResponse::build(StatusCode::RANGE_NOT_SATISFIABLE)
.insert_header((header::CONTENT_RANGE, format!("bytes */{}", file_size)))
.finish();
}
} Prevention
- Never hand-build the Range header; use a helper that emits 'bytes=<start>-<end>'.
- Treat a 416 from actix-files as expected client behaviour, not a server fault.
- Log the raw Range value when investigating to spot malformed clients.
When it happens
Trigger: A GET/HEAD request to a Files or NamedFile route carries a Range header whose syntax is malformed, e.g. 'Range: bytes=abc', 'Range: foo', 'Range: bytes=A-Z', or 'Range: bytes=0x01-0x02'. The first byte after 'bytes=' is not a digit, '-' or space, so read_size in chunked.rs:54-69 (mirrored logic) yields InvalidRange. Any of the negative test cases in range.rs:75-91 reproduce it.
Common situations: Custom client code building the Range header by hand (forgetting 'bytes='), browser extensions injecting bad headers, or curl invocations like 'curl -H "Range: 0-99"'. Also seen when a reverse proxy rewrites or truncates the header.
Related errors
- invalid Range header: range starts after end of content
- 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/30b78b1d8c71ea7c.json.
Report an issue: GitHub.