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

  1. Sniff the first byte: zlib's CMF low nibble is 0x08, and (CMF*256+FLG) % 31 == 0.
  2. Use compress/flate for raw deflate, compress/gzip for gzip, or archive/zip for zip — match the decoder to the actual framing.
  3. Re-check HTTP Content-Encoding; many servers send `gzip` even when the client advertised only `deflate`.
  4. 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

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


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/8ba0b025ac82f2a6. Report an issue: GitHub.