aio-libs/aiohttp · error · ContentEncodingError
Can not decode content-encoding
Error message
Can not decode content-encoding: %s
What it means
Raised as ContentEncodingError when the decompressor fails on a body chunk — i.e. decompressor.decompress_sync raises any Exception. DeflateBuffer.feed_data wraps the call in try/except Exception and re-raises this generic message with the encoding name. It signals corrupt, truncated, or non-conformant compressed payload data for gzip/deflate/br/zstd.
Solutions
- Verify the server sends a correct, complete stream for the declared Content-Encoding.
- Check intermediaries (proxies, firewalls, AV) that may alter body bytes.
- If you intentionally want raw bytes, disable auto-decompress: ClientSession(..., auto_decompress=False).
- Re-fetch to rule out transient corruption; if reproducible, dump the raw bytes and validate with a standalone decompressor.
- Confirm the Accept-Encoding you sent matches what the server actually supports.
Example fix
# before (server mislabels encoding)
return web.Response(body=gzip_data, headers={'Content-Encoding': 'deflate'})
# after (correct header)
return web.Response(body=gzip_data, headers={'Content-Encoding': 'gzip'})
# or, client-side, disable auto-decompress to inspect raw bytes
session = aiohttp.ClientSession(auto_decompress=False) Defensive patterns
Strategy: try-catch
Validate before calling
import zlib, gzip
def validate_gzip_stream(raw: bytes) -> bool:
try:
zlib.decompress(raw, 16 + zlib.MAX_WBITS)
return True
except zlib.error:
return False Try / catch
from aiohttp.http_exceptions import ContentEncodingError
import aiohttp
async def get_with_fallback(url):
try:
async with aiohttp.ClientSession() as s:
async with s.get(url) as r:
return await r.read()
except ContentEncodingError:
# retry with auto_decompress disabled to inspect raw bytes
async with aiohttp.ClientSession(auto_decompress=False) as s:
async with s.get(url) as r:
return await r.read() # caller decompresses manually Prevention
- Verify servers send correct, complete compressed streams.
- Check intermediaries do not corrupt body bytes.
- Use auto_decompress=False to debug raw bytes.
- Confirm Accept-Encoding matches server capabilities.
When it happens
Trigger: The body bytes fed to the decompressor do not form a valid stream for the declared Content-Encoding (gzip/deflate/br/zstd). Examples: truncated gzip stream, wrong algorithm vs header, corrupted bytes, a server sending raw deflate while declaring gzip, or a mid-stream encoding switch.
Common situations: Corrupt response body from a buggy server; a proxy mangling bytes; partial body due to connection drop then resumption; mislabelled Content-Encoding (server says gzip but sends raw bytes); CDN compression mismatch; downloaded file served with wrong encoding header.
Related errors
- deflate
- Can not decode content-encoding: brotli (br). Please…
- Can not decode content-encoding: zstandard (zstd). Please…
- 1009
- Compress wbits must between 9 and 15, zlib does not support…
AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11).
Data as JSON: /api/errors/dff2f9c814d57b10.
Report an issue: GitHub.
Appendix: source
Thrown at aiohttp/http_parser.py:1200
# RFC1950
# bits 0..3 = CM = 0b1000 = 8 = "deflate"
# bits 4..7 = CINFO = 1..7 = windows size.
if self.encoding == "deflate" and chunk[0] & 0xF != 8:
# Change the decoder to decompress incorrectly compressed data
# Actually we should issue a warning about non-RFC-compliant data.
self.decompressor = ZLibDecompressor(
encoding=self.encoding, suppress_deflate_header=True
)
self._started_decoding = True
low_water = self.out._low_water
max_length = (
0 if low_water >= sys.maxsize else max(self._max_decompress_size, low_water)
)
try:
chunk = self.decompressor.decompress_sync(chunk, max_length=max_length)
except Exception:
raise ContentEncodingError(
"Can not decode content-encoding: %s" % self.encoding
)
if chunk:
self.out.feed_data(chunk)
return self.decompressor.data_available
def feed_eof(self) -> None:
chunk = self.decompressor.flush()
# This should never contain data as we defer the call until exhausting
# the decompression. If .flush() is returning data, this may indicate a
# zip bomb vulnerability as it will decompress all remaining data at once.
assert not chunk
if self.size > 0:
# decompressor is not brotli unless encoding is "br"
if self.encoding == "deflate" and not self.decompressor.eof: # type: ignore[union-attr]
raise ContentEncodingError("deflate")View on GitHub (pinned to d041d4d0fd)