encode/httpx · error · DecodingError

{exc}

Error message

{exc}

What it means

DecodingError raised inside DeflateDecoder.decode when zlib.decompress fails on the second (raw deflate) attempt. httpx first tries zlib with default headers, then if that fails retries with -MAX_WBITS (raw deflate); a second failure bubbles up as DecodingError wrapping the underlying zlib.error. This indicates the response body declared 'deflate' Content-Encoding but is not valid zlib or raw-deflate data.

Source

Thrown at httpx/_decoders.py:76

    Handle 'deflate' decoding.

    See: https://stackoverflow.com/questions/1838699
    """

    def __init__(self) -> None:
        self.first_attempt = True
        self.decompressor = zlib.decompressobj()

    def decode(self, data: bytes) -> bytes:
        was_first_attempt = self.first_attempt
        self.first_attempt = False
        try:
            return self.decompressor.decompress(data)
        except zlib.error as exc:
            if was_first_attempt:
                self.decompressor = zlib.decompressobj(-zlib.MAX_WBITS)
                return self.decode(data)
            raise DecodingError(str(exc)) from exc

    def flush(self) -> bytes:
        try:
            return self.decompressor.flush()
        except zlib.error as exc:  # pragma: no cover
            raise DecodingError(str(exc)) from exc


class GZipDecoder(ContentDecoder):
    """
    Handle 'gzip' decoding.

    See: https://stackoverflow.com/questions/1838699
    """

    def __init__(self) -> None:
        self.decompressor = zlib.decompressobj(zlib.MAX_WBITS | 16)

View on GitHub (pinned to b5addb64f0)

Solutions

  1. Reproduce with curl --compressed to confirm the server is genuinely sending bad deflate; file a bug upstream.
  2. Strip Content-Encoding handling by reading raw bytes: iterate resp.iter_raw() instead of resp.iter_bytes().
  3. Disable transparent decoding by removing 'deflate' from client acceptance (set Accept-Encoding: identity).
  4. If the body is actually gzip, ask the server to send correct headers or pre-decode manually with gzip on resp.iter_raw().

Example fix

// before
resp = client.get(url)  # server mislabels deflate
body = resp.content  # DecodingError
// after
resp = client.get(url, headers={'Accept-Encoding': 'identity'})
body = resp.content  # raw bytes; decode manually if needed
Defensive patterns

Strategy: fallback

Validate before calling

# Before issuing, opt out of deflate if you cannot trust the server
headers = {'Accept-Encoding': 'gzip, identity'}  # no deflate
resp = client.get(url, headers=headers)

Try / catch

try:
    body = resp.content
except httpx.DecodingError:
    # server mislabeled deflate; read raw and decode manually or skip
    resp = client.get(url, headers={'Accept-Encoding': 'identity'})
    body = resp.content

Prevention

When it happens

Trigger: Server sending 'Content-Encoding: deflate' but shipping actually-gzip or plain bytes; truncated deflate body (network drop, proxy truncation); server using an undocumented deflate variant; misconfigured origin returning an error page (HTML) with a stale deflate header.

Common situations: Upstream mislabeling encoding; CDN/proxy re-encoding body but not header; connection drops leaving a partial body; some legacy servers serving deflate of gzipped data; testing with a mock that sets the header but not the encoding.

Related errors


AI-assisted analysis of encode/httpx@b5addb64f0 (2026-08-04). Data as JSON: /data/errors/8863799028e3744a.json. Report an issue: GitHub.