golang/go · error

zlib.ErrDictionary

zlib.ErrDictionary

Error message

zlib: invalid dictionary

What it means

Returned when a zlib stream's FDICT flag is set (the stream mandates a preset dictionary) but the caller used NewReader without a dictionary, or when the supplied dictionary's Adler-32 does not match the DICTID field embedded in the stream header. The check happens in the reader's Read/Reset path before deflate decoding begins.

Source

Thrown at src/compress/zlib/reader.go:45

	"bufio"
	"compress/flate"
	"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.

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Use zlib.NewReaderDict(r, dict) with the exact dictionary bytes the producer used.
  2. Ensure the dictionary is byte-identical — Adler-32 is sensitive to a single byte difference; do not re-serialize it.
  3. Distribute dictionaries via content addressing (hash) so producer and consumer load the same artifact.
  4. If you do not have the dictionary, ask the producer to disable preset-dictionary mode (FDICT=0).

Example fix

// before
zr, err := zlib.NewReader(r) // stream has FDICT set
// "zlib: invalid dictionary"

// after: supply the preset dictionary
zr, err := zlib.NewReaderDict(r, sharedDict)
if err != nil { return err }
defer zr.Close()
Defensive patterns

Strategy: validation

Validate before calling

import "hash/adler32"

// If you have a candidate dictionary, verify its Adler-32 matches the
// DICTID embedded in the stream (bytes 2..5, big-endian, when FDICT set).
func dictMatches(streamHead []byte, dict []byte) error {
    if len(streamHead) < 6 { return errors.New("short header") }
    if streamHead[1]&0x20 == 0 { return nil } // FDICT not set
    want := binary.BigEndian.Uint32(streamHead[2:6])
    if adler32.Checksum(dict) != want {
        return zlib.ErrDictionary
    }
    return nil
}

Try / catch

zr, err := zlib.NewReaderDict(r, dict)
if err != nil {
    if errors.Is(err, zlib.ErrDictionary) {
        // Load the correct dictionary artifact or disable FDICT on the producer.
    }
    return err
}

Prevention

When it happens

Trigger: Calling zlib.NewReader on a stream produced with a preset dictionary while providing none; or calling NewReaderDict with a dictionary whose bytes differ from the producer's dictionary (Adler-32 mismatch).

Common situations: HTTP `Accept-Encoding`-style pre-shared dictionaries (e.g., SDCH or shared compression dictionaries), DEFLATE64 with preset dictionaries, decoding a payload compressed by a different service that owns a dict you do not have, or a dict regenerated from a non-deterministic source.

Related errors


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