aio-libs/aiohttp · error · ValueError
compress can not be set if Content-Encoding header is set
Error message
compress can not be set if Content-Encoding header is set
What it means
Raised by ClientRequest._update_content_encoding() when a request supplies both a manually-set Content-Encoding header and a truthy 'compress' parameter. These are mutually exclusive ways to request body compression, so aiohttp refuses the ambiguous combination with ValueError. The method resets self.compress and, if data is present and Content-Encoding is set, any compress!=False triggers the error.
Solutions
- Choose one strategy: either pass compress=True/ 'gzip' and let aiohttp handle it, OR pre-compress the body and set Content-Encoding yourself (with compress=False).
- If you pre-compressed, drop compress or set compress=False.
- If you want aiohttp to compress, remove the manual Content-Encoding header.
- Verify data is non-empty; with no data the method returns early and compression is skipped.
Example fix
# before
await session.post(url, data=gzipped_body,
headers={'Content-Encoding': 'gzip'}, compress=True) # ValueError
# after — let aiohttp compress (recommended)
await session.post(url, data=raw_body, compress='gzip')
# or pre-compress yourself and don't pass compress
await session.post(url, data=gzipped_body, headers={'Content-Encoding': 'gzip'}) Defensive patterns
Strategy: validation
Validate before calling
def prepare_compression(headers, data, compress):
# mutually exclusive: manual Content-Encoding vs compress param
if headers.get('Content-Encoding') and compress:
# pick one strategy
headers.pop('Content-Encoding') # let aiohttp compress
return compress Type guard
def compression_is_unambiguous(headers, compress) -> bool:
return not (headers.get('Content-Encoding') and compress) Try / catch
try:
await session.post(url, data=body, headers=headers, compress=compress)
except ValueError as e:
if 'Content-Encoding header is set' in str(e):
headers.pop('Content-Encoding', None)
await session.post(url, data=body, headers=headers, compress=compress)
else:
raise Prevention
- Pick exactly one compression strategy: the compress param OR a manual header.
- When pre-compressing payloads, set compress=False explicitly.
- Document in code comments which path owns Content-Encoding.
When it happens
Trigger: Calling session.post(url, data=body, headers={'Content-Encoding':'gzip'}, compress=True) — or compress='gzip'. _update_content_encoding sees the existing header plus a truthy compress and raises ValueError.
Common situations: Pre-compressing the body and setting the header, but also passing compress=True; copy-paste mixing two compression strategies; migrating code that manually gzipped payloads to the compress parameter without removing the header.
Related errors
- compress must be one of True, False, 'deflate', or 'gzip'
- chunked can not be set if Content-Length header is set
- chunked can not be set if "Transfer-Encoding: chunked"…
- Invalid Content-Length header
- aiohttp only supports http(s) proxies
AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11).
Data as JSON: /api/errors/bd5ca33822f6fcc7.
Report an issue: GitHub.
Appendix: source
Thrown at aiohttp/client_reqrep.py:1210
del self.headers[hdrs.COOKIE]
for name, value in cookies.items():
# Use helper to preserve coded_value exactly as sent by server
c[name] = preserve_morsel_with_coded_value(value)
self.headers[hdrs.COOKIE] = c.output(header="", sep=";").strip()
def _update_content_encoding(
self, data: Any, compress: bool | Literal["deflate", "gzip"]
) -> None:
"""Set request content encoding."""
self.compress = None
if not data:
return
if self.headers.get(hdrs.CONTENT_ENCODING):
if compress:
raise ValueError(
"compress can not be set if Content-Encoding header is set"
)
elif compress:
if isinstance(compress, str) and compress not in {"deflate", "gzip"}:
raise ValueError(
"compress must be one of True, False, 'deflate', or 'gzip'"
)
self.compress = compress if isinstance(compress, str) else "deflate"
self.headers[hdrs.CONTENT_ENCODING] = self.compress
self.chunked = True # enable chunked, no need to deal with length
def _update_transfer_encoding(self) -> None:
"""Analyze transfer-encoding header."""
te = self.headers.get(hdrs.TRANSFER_ENCODING, "").lower()
if "chunked" in te:
if self.chunked:
raise ValueError(View on GitHub (pinned to d041d4d0fd)