zlib.error Error -3 incorrect header check (tested)
zlib.error: Error -3 while decompressing data: incorrect header check means you handed zlib.decompress() a format it wasn't told to expect. We ran zlib, gzip, raw deflate and plain bytes against every common wbits value, plus truncated and base64 input.
1. incorrect header check = wrong format for the wbits you used
import gzip, zlib
text = b"hello world " * 200
formats = {
"zlib (zlib.compress)": zlib.compress(text),
"gzip (gzip.compress)": gzip.compress(text),
"raw deflate": (lambda c: c.compress(text) + c.flush())(
zlib.compressobj(wbits=-15)),
"not compressed": text,
}
for label, data in formats.items():
print(f"{label:22} first bytes {data[:2].hex()}")
for wbits, name in [(15, "default"), (31, "gzip only"), (-15, "raw only"), (47, "auto")]:
try:
out = zlib.decompress(data, wbits)
print(f" wbits={wbits:3} ({name:9}) OK {len(out)} bytes")
except zlib.error as e:
print(f" wbits={wbits:3} ({name:9}) zlib.error: {e}")
Output:
zlib (zlib.compress) first bytes 789c
wbits= 15 (default ) OK 2400 bytes
wbits= 31 (gzip only) zlib.error: Error -3 while decompressing data: incorrect header check
wbits=-15 (raw only ) zlib.error: Error -3 while decompressing data: invalid stored block lengths
wbits= 47 (auto ) OK 2400 bytes
gzip (gzip.compress) first bytes 1f8b
wbits= 15 (default ) zlib.error: Error -3 while decompressing data: incorrect header check
wbits= 31 (gzip only) OK 2400 bytes
wbits=-15 (raw only ) zlib.error: Error -3 while decompressing data: invalid block type
wbits= 47 (auto ) OK 2400 bytes
raw deflate first bytes cb48
wbits= 15 (default ) zlib.error: Error -3 while decompressing data: incorrect header check
wbits= 31 (gzip only) zlib.error: Error -3 while decompressing data: incorrect header check
wbits=-15 (raw only ) OK 2400 bytes
wbits= 47 (auto ) zlib.error: Error -3 while decompressing data: incorrect header check
not compressed first bytes 6865
wbits= 15 (default ) zlib.error: Error -3 while decompressing data: incorrect header check
wbits= 31 (gzip only) zlib.error: Error -3 while decompressing data: incorrect header check
wbits=-15 (raw only ) zlib.error: Error -3 while decompressing data: invalid stored block lengths
wbits= 47 (auto ) zlib.error: Error -3 while decompressing data: incorrect header check
Measured on Python 3.13.5: zlib.decompress() by default only accepts the zlib format (first bytes 78 9c and friends). Gzip data (1f 8b), raw deflate, and data that isn't compressed all fail with Error -3 while decompressing data: incorrect header check. The fix is the wbits argument:
wbits=31(16+15): gzip only, the same asgzip.decompress().wbits=47(32+15): auto-detects zlib or gzip. It worked for both above.wbits=-15: raw deflate with no header (e.g. zip members, some HTTPdeflatebodies, PHPgzdeflate). Note that auto mode (47) does not detect raw deflate: it gaveincorrect header check.
Using the wrong wbits can also give other Error -3 texts, like invalid stored block lengths or invalid block type: we got those when decoding zlib, gzip and plain bytes as raw deflate.
2. Error -5: incomplete or truncated stream
import zlib
data = zlib.compress(bytes(range(256)) * 400)
cut = data[: len(data) // 2] # download stopped halfway
try:
zlib.decompress(cut)
except zlib.error as e:
print("zlib.decompress:", e)
d = zlib.decompressobj()
out = d.decompress(cut) # streaming API: no exception
print(f"decompressobj: returned {len(out)} bytes, no error; d.eof = {d.eof}")
try:
d.flush()
print("flush(): no error either")
except zlib.error as e:
print("flush():", e)
Output:
zlib.decompress: Error -5 while decompressing data: incomplete or truncated stream
decompressobj: returned 10319 bytes, no error; d.eof = False
flush(): no error either
Measured: half of a valid zlib stream gives Error -5 while decompressing data: incomplete or truncated stream from zlib.decompress(). The streaming decompressobj() API raised nothing: it returned the 10,319 bytes it could decode out of 102,400, and even flush() stayed silent. The only sign was d.eof == False. Check eof after the last chunk whenever you decompress a stream, or you will save truncated data without noticing.
3. Base64 text and str input
import base64, zlib
payload = zlib.compress(b'{"id": 1, "name": "widget"}')
as_b64 = base64.b64encode(payload) # what APIs and JSON fields carry
as_str = payload.decode("latin-1") # bytes that went through a str
for label, data in [("base64 text", as_b64), ("str", as_str)]:
try:
zlib.decompress(data)
except (zlib.error, TypeError) as e:
print(f"{label:12} {type(e).__name__}: {e}")
def smart_decompress(data):
if isinstance(data, str):
data = data.encode("latin-1")
if data[:2] not in (b"\x78\x01", b"\x78\x5e", b"\x78\x9c", b"\x78\xda", b"\x1f\x8b"):
try: # maybe base64 of compressed data
data = base64.b64decode(data, validate=True)
except ValueError:
pass
for wbits in (47, -15): # zlib/gzip auto, then raw deflate
try:
return zlib.decompress(data, wbits)
except zlib.error as e:
err = e
raise err
print("smart:", smart_decompress(as_b64))
print("smart:", smart_decompress(as_str))
Output:
base64 text error: Error -3 while decompressing data: incorrect header check
str TypeError: a bytes-like object is required, not 'str'
smart: b'{"id": 1, "name": "widget"}'
smart: b'{"id": 1, "name": "widget"}'
Measured: compressed bytes often travel as base64 inside JSON or HTTP headers. Passing the base64 text straight to zlib.decompress() gives incorrect header check, so decode it with base64.b64decode() first. A str raises TypeError: a bytes-like object is required. Bytes that were decoded into a str through Latin-1 can be recovered with .encode("latin-1"); other text encodings (UTF-8 with errors="replace", for example) lose bytes for good. The helper above sniffs the header, tries base64, then tries wbits=47 and -15, and decoded both inputs. If you got the data from requests, you usually don't need zlib at all: requests already decompresses gzip and deflate response bodies listed in Content-Encoding, so r.content is plain.
Frequently asked questions
What does zlib.error: Error -3 while decompressing data: incorrect header check mean?
The data isn't in the format the wbits value expects. We measured gzip, raw deflate, base64 text and uncompressed bytes all giving it with the default wbits; use wbits=47 for zlib or gzip, -15 for raw deflate.
How do I decompress gzip data with zlib?
zlib.decompress(data, 31) for gzip only, or 47 to auto-detect zlib and gzip. We measured both working on gzip.compress() output.
What does Error -5 incomplete or truncated stream mean?
The compressed data was cut off. We measured it with half of a valid stream; decompressobj() returned partial data with no error, so check d.eof.
Does wbits=47 handle raw deflate?
No. We measured auto mode (47) failing on raw deflate with incorrect header check; raw deflate needs wbits=-15.
Why does zlib.decompress fail on base64 data?
Base64 text isn't compressed bytes. Decode it with base64.b64decode() first; we measured the direct call giving incorrect header check.
Written with AI assistance. Measured on 2026-10-09 on Debian with Python 3.13.5's zlib: zlib, gzip, raw deflate and uncompressed input against wbits 15, 31, -15 and 47; a truncated stream through decompress() and decompressobj(); base64 and str input. Every block was run verbatim and its output pasted from that run. PlainHeaders is our extension; Python's zlib is built in.