aio-libs/aiohttp · error · RuntimeError

The zstd decompression is not available. Please install `bac

Error message

The zstd decompression is not available. Please install `backports.zstd` module

What it means

Raised when constructing ZSTDDecompressor while neither the stdlib `zstandard`/`zstd` module nor the `backports.zstd` fallback is importable (HAS_ZSTD is False). It fires the first time aiohttp tries to decode a response with `Content-Encoding: zstd`. The message recommends `backports.zstd` specifically because that is what the import guard looks for.

Source

Thrown at aiohttp/compression_utils.py:394

    def flush(self) -> bytes:
        """Flush the decompressor."""
        if hasattr(self._obj, "flush"):
            return cast(bytes, self._obj.flush())
        return b""

    @property
    def data_available(self) -> bool:
        return not self._obj.is_finished() and not self._last_empty


class ZSTDDecompressor(DecompressionBaseHandler):
    def __init__(
        self,
        executor: Executor | None = None,
        max_sync_chunk_size: int | None = MAX_SYNC_CHUNK_SIZE,
    ) -> None:
        if not HAS_ZSTD:
            raise RuntimeError(
                "The zstd decompression is not available. "
                "Please install `backports.zstd` module"
            )
        self._obj = ZstdDecompressor()
        self._pending_unused_data: bytes | None = None
        super().__init__(executor=executor, max_sync_chunk_size=max_sync_chunk_size)

    def decompress_sync(
        self, data: bytes, max_length: int = ZLIB_MAX_LENGTH_UNLIMITED
    ) -> bytes:
        # zstd uses -1 for unlimited, while zlib uses 0 for unlimited
        # Convert the zlib convention (0=unlimited) to zstd convention (-1=unlimited)
        zstd_max_length = (
            ZSTD_MAX_LENGTH_UNLIMITED
            if max_length == ZLIB_MAX_LENGTH_UNLIMITED
            else max_length
        )
        if self._pending_unused_data is not None:

View on GitHub (pinned to c0ef574e29)

Solutions

  1. Install the codec: `pip install backports.zstd` (or use Python 3.14+ which ships zstdlib).
  2. Disable zstd negotiation by setting `Accept-Encoding: gzip, deflate, br` so the server never picks zstd.
  3. Verify the install in CI with `python -c "import zstandard; print(zstandard.__version__)"`.

Example fix

# before
# zstd not importable -> RuntimeError on resp.text()
# after
# requirements.txt
backports.zstd>=1.0
Defensive patterns

Strategy: validation

Validate before calling

def zstd_available() -> bool:
    try:
        import zstandard  # noqa: F401
        return True
    except ImportError:
        try:
            import backports.zstd  # noqa: F401
            return True
        except ImportError:
            return False

Try / catch

try:
    body = await resp.read()
except RuntimeError as e:
    if 'zstd' in str(e).lower():
        # retry without 'zstd' in Accept-Encoding
        ...
    raise

Prevention

When it happens

Trigger: Server returns `Content-Encoding: zstd` and the client environment lacks zstd support, then the response body is read and ZSTDDecompressor is instantiated.

Common situations: CDN/server upgraded to advertise zstd but the client image lacks the dep. Older Python (<3.14) without stdlib zstd and no backport installed. Cached environments where the package was removed by a cleanup step.

Related errors


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