encode/httpx · error · ImportError
Using 'BrotliDecoder', but neither of the 'brotlicffi' or…
Error message
Using 'BrotliDecoder', but neither of the 'brotlicffi' or 'brotli' packages have been installed. Make sure to install httpx using `pip install httpx[brotli]`.
What it means
ImportError raised in BrotliDecoder.__init__ when neither the brotli nor brotlicffi package is importable but a response arrives with 'Content-Encoding: br'. httpx lazily registers the 'br' decoder only if a brotli library is present at import time (SUPPORTED_DECODERS.pop('br') otherwise), so this firing means the library became available at decoder-construction time inconsistently, or the decoder was constructed manually. The fix is to install the optional brotli extra.
Solutions
- Install the extra: `pip install httpx[brotli]` (pulls brotli on CPython, brotlicffi on PyPy).
- Alternatively `pip install brotli` (or brotlicffi on PyPy).
- Pin the extra in requirements.txt/pyproject: `httpx[brotli]>=0.27`.
- If you cannot install, avoid br by sending Accept-Encoding: gzip, deflate (no br) so the server won't brotli-encode.
Example fix
// before
pip install httpx
resp = client.get(url) # server sends Content-Encoding: br
resp.content # ImportError
// after
pip install 'httpx[brotli]'
# or, without installing, opt out of br:
resp = client.get(url, headers={'Accept-Encoding': 'gzip, deflate'}) Defensive patterns
Strategy: validation
Validate before calling
# Detect missing brotli before sending
try:
import brotli # noqa: F401
HAS_BROTLI = True
except ImportError:
HAS_BROTLI = False
headers = {'Accept-Encoding': 'gzip, deflate, br'} if HAS_BROTLI else {'Accept-Encoding': 'gzip, deflate'}
resp = client.get(url, headers=headers) Type guard
def supports_brotli() -> bool:
try:
import brotli # noqa: F401
return True
except ImportError:
try:
import brotlicffi # noqa: F401
return True
except ImportError:
return False Try / catch
try:
body = resp.content
except ImportError as exc:
if 'brotli' in str(exc).lower():
import subprocess; subprocess.check_call(['pip', 'install', 'httpx[brotli]'])
# then re-request
else:
raise Prevention
- Install httpx with extras: pip install 'httpx[brotli,zstd]'.
- Declare extras in pyproject/requirements, not just plain httpx.
- Match Accept-Encoding to actually-installed codecs.
- Pin dependency versions to avoid wheel regressions.
When it happens
Trigger: Response with 'Content-Encoding: br' when httpx was installed without the brotli extra; manually instantiating BrotliDecoder() in tests; environment where brotli was uninstalled/locked out after httpx imported; CI image missing the C brotli library.
Common situations: Fresh pip install httpx without extras hitting a brotli-compressed CDN (Cloudflare, Google often send br); deploying to a slim Docker image; upgrading Python without reinstalling binary wheels; dev-vs-prod dependency mismatch (extras only in requirements-dev).
Related errors
AI-assisted analysis of encode/httpx@b5addb64f0 (2026-08-04).
Data as JSON: /api/errors/b971cf9aa797d96b.
Report an issue: GitHub.
Appendix: source
Thrown at httpx/_decoders.py:120
try:
return self.decompressor.flush()
except zlib.error as exc: # pragma: no cover
raise DecodingError(str(exc)) from exc
class BrotliDecoder(ContentDecoder):
"""
Handle 'brotli' decoding.
Requires `pip install brotlipy`. See: https://brotlipy.readthedocs.io/
or `pip install brotli`. See https://github.com/google/brotli
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) -> None:
if brotli is None: # pragma: no cover
raise ImportError(
"Using 'BrotliDecoder', but neither of the 'brotlicffi' or 'brotli' "
"packages have been installed. "
"Make sure to install httpx using `pip install httpx[brotli]`."
) from None
self.decompressor = brotli.Decompressor()
self.seen_data = False
self._decompress: typing.Callable[[bytes], bytes]
if hasattr(self.decompressor, "decompress"):
# The 'brotlicffi' package.
self._decompress = self.decompressor.decompress # pragma: no cover
else:
# The 'brotli' package.
self._decompress = self.decompressor.process # pragma: no cover
def decode(self, data: bytes) -> bytes:
if not data:
return b""View on GitHub (pinned to b5addb64f0)