aio-libs/aiohttp · warning · ValueError

range not in acceptable format

Error message

range not in acceptable format

What it means

Raised as ValueError by BaseRequest.http_range (aiohttp/web_request.py:613) when the Range header is present but does not match the regex '^bytes=(\d*)-(\d*)$'. aiohttp only supports the RFC 7233 'bytes=' range unit; any other unit (e.g. 'items='), missing '=' , extra whitespace, or malformed syntax causes re.findall to return no groups and IndexError is caught and re-raised as this ValueError.

Source

Thrown at aiohttp/web_request.py:613

        parsed = parse_cookie_header(self.headers.get(hdrs.COOKIE, ""))
        # Extract values from Morsel objects
        return MappingProxyType({name: morsel.value for name, morsel in parsed})

    @reify
    def http_range(self) -> "slice[int, int, int]":
        """The content of Range HTTP header.

        Return a slice instance.

        """
        rng = self._headers.get(hdrs.RANGE)
        start, end = None, None
        if rng is not None:
            try:
                pattern = r"^bytes=(\d*)-(\d*)$"
                start, end = re.findall(pattern, rng, re.ASCII)[0]
            except IndexError:  # pattern was not found in header
                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")

View on GitHub (pinned to c0ef574e29)

Solutions

  1. Validate the Range header format before relying on request.http_range, returning HTTPRequestedRangeNotSatisfiable or HTTPBadRequest on parse failure.
  2. Wrap request.http_range access in try/except ValueError and treat it as 'no range requested'.
  3. Make sure clients send 'Range: bytes=start-end' exactly (lowercase 'bytes=' allowed, but the unit must be bytes).

Example fix

// before
rng = request.http_range  # ValueError on bad header

# after
try:
    rng = request.http_range
except ValueError:
    raise web.HTTPBadRequest(text="Invalid Range header")
Defensive patterns

Strategy: try-catch

Validate before calling

import re
rng = request.headers.get("Range", "")
if rng and not re.match(r"^bytes=\d*-\d*$", rng):
    raise web.HTTPBadRequest(text="Invalid Range header")

Type guard

def is_valid_range_header(value: str) -> bool:
    import re
    return bool(re.match(r"^bytes=\d*-\d*$", value))

Try / catch

try:
    rng = request.http_range
except ValueError:
    raise web.HTTPBadRequest(text="Invalid Range header")

Prevention

When it happens

Trigger: Accessing request.http_range (directly or via FileResponse, which reads it implicitly) on a request whose Range header looks like 'items=0-10', 'bytes 0-10' (space instead of =), 'bytes=-', or '0-10' (missing 'bytes=' prefix).

Common situations: Custom clients sending non-standard range units; copy-pasted Range header from a different protocol (WebDAV, S3 partial-object); proxies that rewrite or corrupt Range; tests with manually crafted headers.

Related errors


AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04). Data as JSON: /data/errors/e7f97e93bd3ac5a4.json. Report an issue: GitHub.