aio-libs/aiohttp · error · RuntimeError

Using chunked encoding is forbidden for HTTP/{major}.{minor}

Error message

Using chunked encoding is forbidden for HTTP/{major}.{minor}

What it means

Chunked transfer-encoding is only valid for HTTP/1.1. If you enable chunked via enable_chunked_encoding() but the client negotiated HTTP/1.0, _prepare_headers raises RuntimeError at line 392-396 rather than emitting an invalid response.

Source

Thrown at aiohttp/web_response.py:393

        writer = self._payload_writer
        assert writer is not None
        keep_alive = self._keep_alive
        if keep_alive is None:
            keep_alive = request.keep_alive
        self._keep_alive = keep_alive

        version = request.version

        headers = self._headers
        if self._cookies:
            populate_with_cookies(headers, self._cookies)

        if self._compression:
            await self._start_compression(request)

        if self._chunked:
            if version != HttpVersion11:
                raise RuntimeError(
                    "Using chunked encoding is forbidden "
                    f"for HTTP/{request.version.major}.{request.version.minor}"
                )
            if not self._must_be_empty_body:
                writer.enable_chunking()
                headers[hdrs.TRANSFER_ENCODING] = "chunked"
        elif self._length_check:  # Disabled for WebSockets
            writer.length = self.content_length
            if writer.length is None:
                if version >= HttpVersion11:
                    if not self._must_be_empty_body:
                        writer.enable_chunking()
                        headers[hdrs.TRANSFER_ENCODING] = "chunked"
                elif not self._must_be_empty_body:
                    keep_alive = False

        # HTTP 1.1: https://tools.ietf.org/html/rfc7230#section-3.3.2
        # HTTP 1.0: https://tools.ietf.org/html/rfc1945#section-10.4

View on GitHub (pinned to c0ef574e29)

Solutions

  1. Don't force chunked; let aiohttp auto-decide based on request version (it falls back to closing the connection for HTTP/1.0 at lines 407-408).
  2. Require HTTP/1.1 from clients if you must use chunked streaming.
  3. Remove the resp.enable_chunked_encoding() call entirely.

Example fix

# before
resp = StreamResponse()
resp.enable_chunked_encoding()  # breaks HTTP/1.0 clients

# after
resp = StreamResponse()  # aiohttp auto-enables chunked for 1.1, closes conn for 1.0
Defensive patterns

Strategy: validation

Validate before calling

# Don't force chunked; let aiohttp decide. If you must, gate on request version:
from aiohttp import HttpVersion11

if request.version == HttpVersion11:
    resp.enable_chunked_encoding()

Try / catch

try:
    await resp.prepare(request)
except RuntimeError as e:
    if 'chunked encoding is forbidden' in str(e):
        # client is HTTP/1.0; fall back to connection-close streaming
        ...

Prevention

When it happens

Trigger: Calling resp.enable_chunked_encoding() and serving a client that sent an HTTP/1.0 request line (request.version != HttpVersion11). The version comes from the parsed request, so this depends on what the client sent, not on server config.

Common situations: Testing against an HTTP/1.0-only client or proxy (curl --http1.0, legacy tools); an upstream proxy downgrading the protocol; forcing chunked for streaming then hitting an old client.

Related errors


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