aio-libs/aiohttp · error · RuntimeError

The brotli decompression is not available. Please install…

Error message

The brotli decompression is not available. Please install `Brotli` module

What it means

Raised by BrotliDecompressor.__init__ when neither the brotli nor brotlicffi module could be imported at startup (HAS_BROTLI is False). aiohttp advertises 'br' in Accept-Encoding only when brotli support is detected, but if a response still arrives as Content-Encoding: br (e.g. forced by a custom headers override, a proxy, or a stale session), the decompressor is constructed and aborts immediately. Installing the optional dependency is the supported fix.

Solutions

  1. Install the dependency: pip install Brotli (or pip install brotlicffi on PyPy/locked-down envs).
  2. Install aiohttp with the relevant extra, e.g. pip install 'aiohttp[spdylite]' where applicable.
  3. Stop forcing Accept-Encoding: br in custom request headers when brotli is not installed.
  4. If you cannot add deps, configure the server/proxy to send gzip or identity instead.

Example fix

# shell
# before: aiohttp installed without brotli
pip install Brotli
# or pin brotlicffi for environments without the C toolchain
pip install brotlicffi
Defensive patterns

Strategy: fallback

Validate before calling

try:
    import brotli  # noqa: F401
    HAS_BROTLI = True
except ImportError:
    HAS_BROTLI = False

headers = {'Accept-Encoding': 'gzip, identity'} if not HAS_BROTLI else {'Accept-Encoding': 'gzip, br'}
await session.get(url, headers=headers)

Type guard

null

Try / catch

try:
    data = await resp.read()
except RuntimeError as exc:
    if 'brotli' in str(exc).lower():
        raise RuntimeError('install Brotli or drop br from Accept-Encoding') from exc
    raise

Prevention

When it happens

Trigger: Server returns Content-Encoding: br but aiohttp was installed without the brotli extra; a reverse proxy rewrites responses to br regardless of Accept-Encoding; manual headers={'Accept-Encoding': 'br'} sent even though brotli is absent.

Common situations: Fresh pip install aiohttp without extras in a slim container; CI image missing the optional C library; pinning aiohttp to a version where the extra was renamed; brotlicffi present but import broken on the platform.

Related errors


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

Appendix: source

Thrown at aiohttp/compression_utils.py:439

        )

    @property
    def eof(self) -> bool:
        return self._decompressor.eof


class BrotliDecompressor(DecompressionBaseHandler):
    # Supports both 'brotlipy' and 'Brotli' packages
    # since they share an import name. The top branches
    # are for 'brotlipy' and bottom branches for 'Brotli'
    def __init__(
        self,
        executor: Executor | None = None,
        max_sync_chunk_size: int | None = MAX_SYNC_CHUNK_SIZE,
    ) -> None:
        """Decompress data using the Brotli library."""
        if not HAS_BROTLI:
            raise RuntimeError(
                "The brotli decompression is not available. "
                "Please install `Brotli` module"
            )
        self._obj = brotli.Decompressor()
        self._last_empty = False
        super().__init__(executor=executor, max_sync_chunk_size=max_sync_chunk_size)

    def decompress_sync(
        self, data: Buffer, max_length: int = ZLIB_MAX_LENGTH_UNLIMITED
    ) -> bytes:
        """Decompress the given data."""
        if hasattr(self._obj, "decompress"):
            if max_length == ZLIB_MAX_LENGTH_UNLIMITED:
                result = cast(bytes, self._obj.decompress(data))
            else:
                result = cast(bytes, self._obj.decompress(data, max_length))
        else:
            if max_length == ZLIB_MAX_LENGTH_UNLIMITED:

View on GitHub (pinned to d041d4d0fd)