aio-libs/aiohttp · error · RuntimeError

You can't set content length when chunked encoding is enable

Error message

You can't set content length when chunked encoding is enable

What it means

Raised as RuntimeError by StreamResponse.content_length setter (aiohttp/web_response.py:213) when self._chunked is already True. This is the symmetric counterpart to error 218: once Transfer-Encoding: chunked has been enabled, you cannot also set Content-Length because HTTP forbids mixing the two framing styles.

Source

Thrown at aiohttp/web_response.py:213

        self._compression = True
        self._compression_force = force
        self._compression_strategy = strategy

    @property
    def headers(self) -> "CIMultiDict[str]":
        return self._headers

    @property
    def content_length(self) -> int | None:
        # Just a placeholder for adding setter
        return super().content_length

    @content_length.setter
    def content_length(self, value: int | None) -> None:
        if value is not None:
            value = int(value)
            if self._chunked:
                raise RuntimeError(
                    "You can't set content length when chunked encoding is enable"
                )
            self._headers[hdrs.CONTENT_LENGTH] = str(value)
        else:
            self._headers.pop(hdrs.CONTENT_LENGTH, None)

    @property
    def content_type(self) -> str:
        # Just a placeholder for adding setter
        return super().content_type

    @content_type.setter
    def content_type(self, value: str) -> None:
        self.content_type  # read header values if needed
        self._content_type = str(value)
        self._generate_content_type_header()

    @property

View on GitHub (pinned to c0ef574e29)

Solutions

  1. Pick one framing strategy and stick with it for the lifetime of the response.
  2. If you previously called enable_chunked_encoding(), do not set content_length afterwards - chunked bodies have unknown length by definition.
  3. Reset chunked mode (construct a new StreamResponse) if you genuinely need to switch back to a fixed length.

Example fix

// before
resp = web.StreamResponse()
resp.enable_chunked_encoding()
resp.content_length = 100  # RuntimeError


# after (option A: fixed length)
resp = web.StreamResponse()
resp.content_length = 100

# after (option B: chunked, no length)
resp = web.StreamResponse()
resp.enable_chunked_encoding()
Defensive patterns

Strategy: validation

Validate before calling

if not resp._chunked:
    resp.content_length = 100

Type guard

def can_set_content_length(resp: web.StreamResponse) -> bool:
    return not getattr(resp, "_chunked", False)

Try / catch

try:
    resp.content_length = 100
except RuntimeError:
    # response is chunked; construct a new non-chunked response instead
    raise

Prevention

When it happens

Trigger: Calling resp.enable_chunked_encoding() first, then assigning resp.content_length = N. Also triggered by code paths that auto-set content_length (e.g. after writing a known-size body) on a response that was already put into chunked mode.

Common situations: Middleware that forces chunked encoding on all responses conflicting with code that fixes a Content-Length; refactoring a handler from fixed-length to streaming but leaving the content_length assignment; copy-pasting code that mixed both patterns.

Related errors


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