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
- Use zlib.NewReaderDict(r, dict) with the exact dictionary bytes the producer used.
- Ensure the dictionary is byte-identical — Adler-32 is sensitive to a single byte difference; do not re-serialize it.
- Distribute dictionaries via content addressing (hash) so producer and consumer load the same artifact.
- 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
- Distribute dictionaries via content-hash addressing.
- Never re-serialize dictionaries — Adler-32 is sensitive to single bytes.
- Document the FDICT contract clearly for any peer service producing streams.
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
- zlib.ErrHeader
- 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/b5f4fb2bebf8a157.
Report an issue: GitHub.