golang/go · error
zlib.ErrHeader
zlib.ErrHeader
Error message
zlib: invalid header
What it means
Returned when the zlib header (the two CMF/FLG bytes) fails RFC 1950 validation: CM must be 8 (deflate), CINFO must encode a window size <= 7 (32 KiB), the FCHECK field must make the two-byte header a multiple of 31, and FLEVEL is informational. Any deviation aborts before deflate decoding starts.
Source
Thrown at src/compress/zlib/reader.go:47
"encoding/binary"
"errors"
"hash"
"hash/adler32"
"io"
)
const (
zlibDeflate = 8
zlibMaxWindow = 7
)
var (
// ErrChecksum is returned when reading ZLIB data that has an invalid checksum.
ErrChecksum = errors.New("zlib: invalid checksum")
// ErrDictionary is returned when reading ZLIB data that has an invalid dictionary.
ErrDictionary = errors.New("zlib: invalid dictionary")
// ErrHeader is returned when reading ZLIB data that has an invalid header.
ErrHeader = errors.New("zlib: invalid header")
)
type reader struct {
r flate.Reader
decompressor io.ReadCloser
digest hash.Hash32
err error
scratch [4]byte
}
// Resetter resets a ReadCloser returned by [NewReader] or [NewReaderDict]
// to switch to a new underlying Reader. This permits reusing a ReadCloser
// instead of allocating a new one.
type Resetter interface {
// Reset discards any buffered data and resets the Resetter as if it was
// newly initialized with the given reader.
Reset(r io.Reader, dict []byte) error
}View on GitHub (pinned to b6b368adc5)
Solutions
- Sniff the first byte: zlib's CMF low nibble is 0x08, and (CMF*256+FLG) % 31 == 0.
- Use compress/flate for raw deflate, compress/gzip for gzip, or archive/zip for zip — match the decoder to the actual framing.
- Re-check HTTP Content-Encoding; many servers send `gzip` even when the client advertised only `deflate`.
- If you receive raw deflate from a peer, frame it yourself: prepend a valid zlib header or use flate.NewReader directly.
Example fix
// before zr, err := zlib.NewReader(body) // body is raw deflate // "zlib: invalid header" // after: use the right reader for raw deflate fr := flate.NewReader(body) defer fr.Close() io.Copy(out, fr)
Defensive patterns
Strategy: validation
Validate before calling
func isZlibStream(r io.Reader) (io.Reader, bool) {
br := bufio.NewReader(r)
b, err := br.Peek(2)
if err != nil || len(b) < 2 { return br, false }
cmf, flg := b[0], b[1]
if cmf&0x0f != 8 { return br, false }
if (uint16(cmf)<<8 | uint16(flg)) % 31 != 0 { return br, false }
return br, true
} Try / catch
zr, err := zlib.NewReader(r)
if err != nil {
if errors.Is(err, zlib.ErrHeader) {
// Try gzip.NewReader or flate.NewReader as a fallback.
return tryOtherCodecs(r)
}
return err
} Prevention
- Sniff CMF/FLG before constructing the reader.
- Map Content-Encoding to the correct decoder explicitly.
- Distinguish raw deflate from zlib-framed deflate at protocol design time.
When it happens
Trigger: Calling zlib.NewReader on data that is not a zlib stream — raw deflate (no header), gzip (different magic), an uncompressed payload, or a corrupt header where the FCHECK modulo-31 invariant fails.
Common situations: Mis-routing format choice: HTTP server sends gzip but client uses zlib.NewReader; websocket DEFLATE frames whose client-to-server/no-context-takeover stripping left a raw-deflate body; PNG IDAT chunks are zlib-wrapped but raw deflate is sometimes mis-attempted.
Related errors
- zlib.ErrDictionary
- gzip.ErrHeader
- gzip.Write: Extra data is too large
- gzip.Write: non-Latin-1 header string
- zlib.ErrChecksum
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/8ba0b025ac82f2a6.
Report an issue: GitHub.