aio-libs/aiohttp · warning · ValueError
No start or end of range specified
Error message
No start or end of range specified
What it means
Raised as ValueError by BaseRequest.http_range (aiohttp/web_request.py:631) when the Range header matched the byte syntax but both captured groups were empty - i.e. literally 'Range: bytes=-'. aiohttp has no start and no end to compute a slice from, so the parsed range is meaningless and it raises rather than return a degenerate slice(None, None, 1).
Source
Thrown at aiohttp/web_request.py:631
raise ValueError("range not in acceptable format")
end = int(end) if end else None
start = int(start) if start else None
if start is None and end is not None:
# end with no start is to return tail of content
start = -end
end = None
if start is not None and end is not None:
# end is inclusive in range header, exclusive for slice
end += 1
if start >= end:
raise ValueError("start cannot be after end")
if start is end is None: # No valid range supplied
raise ValueError("No start or end of range specified")
return slice(start, end, 1)
@reify
def content(self) -> StreamReader:
"""Return raw payload stream."""
return self._payload
@property
def can_read_body(self) -> bool:
"""Return True if request's HTTP BODY can be read, False otherwise."""
return not self._payload.at_eof()
@reify
def body_exists(self) -> bool:
"""Return True if request has HTTP BODY, False otherwise."""
return type(self._payload) is not EmptyStreamReader
View on GitHub (pinned to c0ef574e29)
Solutions
- Wrap request.http_range access in try/except ValueError and treat it as 'no range requested' (serve full body).
- Return HTTPRequestedRangeNotSatisfiable (416) if you want strict semantics.
- Audit upstream clients / proxies that emit 'bytes=-' to confirm they actually want a partial response.
Example fix
// before
rng = request.http_range # raises on 'bytes=-'
# after
try:
rng = request.http_range
except ValueError:
rng = slice(None, None, 1) # treat as full body Defensive patterns
Strategy: try-catch
Validate before calling
if request.headers.get("Range") == "bytes=-":
rng = slice(None, None, 1)
else:
rng = request.http_range Type guard
def is_meaningful_range(value: str) -> bool:
return value != "bytes=-" Try / catch
try:
rng = request.http_range
except ValueError:
rng = slice(None, None, 1) # treat as full body Prevention
- Treat 'bytes=-' as 'no range' rather than an error if you want lenient behavior.
- Audit upstream clients/proxies emitting degenerate ranges.
- Document whether your endpoint returns 416 or the full body for empty ranges.
When it happens
Trigger: A client sending 'Range: bytes=-' (empty start and empty end) - typically a buggy download client or a probe. Because the regex '(\d*)-(\d*)' accepts empty captures, only the explicit None/None check on line 630 catches it.
Common situations: Misbehaving clients (some old Android download managers, curl edge cases); corrupted header from a proxy; manual tests that hardcode 'bytes=-'.
Related errors
- range not in acceptable format
- start cannot be after end
- Method cannot contain non-token characters {method!r} (found
- Invalid Content-Length header: {content_length_hdr!r}
- compress must be one of True, False, 'deflate', or 'gzip'
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/7bf577f67e583a76.json.
Report an issue: GitHub.