aio-libs/aiohttp · error · ValueError

chunked can not be set if Content-Length header is set

Error message

chunked can not be set if Content-Length header is set

What it means

Raised as ValueError in _update_transfer_encoding() when self.chunked is True and the request also carries a Content-Length header. HTTP semantics forbid advertising both a fixed length and chunked transfer encoding on the same request; the two framing mechanisms are mutually exclusive.

Source

Thrown at aiohttp/client_reqrep.py:1235

                )
            self.compress = compress if isinstance(compress, str) else "deflate"
            self.headers[hdrs.CONTENT_ENCODING] = self.compress
            self.chunked = True  # enable chunked, no need to deal with length

    def _update_transfer_encoding(self) -> None:
        """Analyze transfer-encoding header."""
        te = self.headers.get(hdrs.TRANSFER_ENCODING, "").lower()

        if "chunked" in te:
            if self.chunked:
                raise ValueError(
                    "chunked can not be set "
                    'if "Transfer-Encoding: chunked" header is set'
                )

        elif self.chunked:
            if hdrs.CONTENT_LENGTH in self.headers:
                raise ValueError(
                    "chunked can not be set if Content-Length header is set"
                )

            self.headers[hdrs.TRANSFER_ENCODING] = "chunked"

    def _update_body_from_data(self, body: Any) -> None:
        """Update request body from data."""
        if body is None:
            self._body = self._EMPTY_BODY
            # Set Content-Length to 0 when body is None for methods that expect a body
            if (
                self.method not in self.GET_METHODS
                and not self.chunked
                and hdrs.CONTENT_LENGTH not in self.headers
            ):
                self.headers[hdrs.CONTENT_LENGTH] = "0"
            return

View on GitHub (pinned to c0ef574e29)

Solutions

  1. Do not set Content-Length when using chunked=True or streaming bodies.
  2. Let aiohttp compute framing: it picks Content-Length for fixed bytes and chunked for streams.
  3. Remove any manually-set Content-Length header before sending a streaming body.
  4. Buffer the body into bytes first if you need a fixed Content-Length.

Example fix

# before
await session.post(url, data=async_generator(),
                  chunked=True,
                  headers={'Content-Length': '1024'})
# after - let aiohttp decide framing
await session.post(url, data=async_generator(), chunked=True)
# or buffer first
body = b''.join([chunk async for chunk in gen])
await session.post(url, data=body)  # Content-Length auto-set
Defensive patterns

Strategy: validation

Validate before calling

if chunked and 'Content-Length' in headers:
    del headers['Content-Length']  # chunked and length are mutually exclusive

Prevention

When it happens

Trigger: Fires at line 1233-1237 when chunked flag is True, no Transfer-Encoding header is set, but CONTENT_LENGTH is present in headers. Triggered by passing chunked=True together with a Content-Length header, or when a body sets Content-Length and chunked is forced on.

Common situations: Forcing chunked=True for a streaming body while a middleware also sets Content-Length; manually setting Content-Length on a request with a generator/async-generator body (which aiohttp auto-chunks).

Related errors


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