aio-libs/aiohttp · error · RuntimeError

Cannot compute fallback encoding of a not yet read body

Error message

Cannot compute fallback encoding of a not yet read body

What it means

Raised by ClientResponse.get_encoding() when no charset can be determined from the Content-Type header or mimetype defaults, and the response body has not been read yet. get_encoding() falls back to charset detection on self._body, but if _body is None (unread) it cannot run the detector and raises RuntimeError. This typically means get_encoding()/text()/json() was called before read() in a streaming context.

Solutions

  1. Call await resp.read() before resp.get_encoding() so _body is populated.
  2. Prefer resp.text() / resp.json() which call read() internally.
  3. If you control the server, send an explicit charset: 'Content-Type: text/html; charset=utf-8'.
  4. Pass encoding explicitly to text(encoding='utf-8') to bypass detection.

Example fix

# before
enc = resp.get_encoding()  # _body is None -> RuntimeError
body = await resp.read()

# after
body = await resp.read()
enc = resp.get_encoding()  # now _body is available for fallback detection
Defensive patterns

Strategy: validation

Validate before calling

async def safe_get_encoding(resp) -> str:
    if resp._body is None:
        await resp.read()  # populate body before detection
    return resp.get_encoding()

Type guard

def body_is_read(resp) -> bool:
    return getattr(resp, '_body', None) is not None

Try / catch

try:
    enc = resp.get_encoding()
except RuntimeError as e:
    if 'not yet read body' in str(e):
        await resp.read()
        enc = resp.get_encoding()
    else:
        raise

Prevention

When it happens

Trigger: Calling resp.get_encoding() (or resp.text()/resp.json() in a path where read() hasn't populated _body) on a response whose Content-Type has no charset and is not JSON/RDAP, while _body is still None. text()/json() normally call read() first, so this most often arises from calling get_encoding() directly or from a custom code path.

Common situations: Calling get_encoding() manually before reading the body; a response with 'Content-Type: text/html' (no charset) where the app tries to detect encoding prematurely; subclassing ClientResponse and invoking encoding logic out of order.

Related errors


AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11). Data as JSON: /api/errors/efe0c08e8859dd4a. Report an issue: GitHub.

Appendix: source

Thrown at aiohttp/client_reqrep.py:730

    def get_encoding(self) -> str:
        ctype = self.headers.get(hdrs.CONTENT_TYPE, "").lower()
        mimetype = parse_mimetype(ctype)

        encoding = mimetype.parameters.get("charset")
        if encoding:
            with contextlib.suppress(LookupError, ValueError):
                return codecs.lookup(encoding).name

        if mimetype.type == "application" and (
            mimetype.subtype == "json" or mimetype.subtype == "rdap"
        ):
            # RFC 7159 states that the default encoding is UTF-8.
            # RFC 7483 defines application/rdap+json
            return "utf-8"

        if self._body is None:
            raise RuntimeError(
                "Cannot compute fallback encoding of a not yet read body"
            )

        return self._resolve_charset(self, self._body)

    async def text(self, encoding: str | None = None, errors: str = "strict") -> str:
        """Read response payload and decode."""
        await self.read()

        if encoding is None:
            encoding = self.get_encoding()

        return self._body.decode(encoding, errors=errors)  # type: ignore[union-attr]

    async def json(
        self,
        *,
        encoding: str | None = None,

View on GitHub (pinned to d041d4d0fd)