golang/go · error
gzip.ErrChecksum
gzip.ErrChecksum
Error message
gzip: invalid checksum
What it means
Returned by gzip.Reader.Read when the CRC32 of the decompressed bytes (or the ISIZE length field) does not match the trailer recorded in the GZIP stream. The library computes the CRC32 incrementally while decompressing and compares it against the last 8 bytes of the stream once EOF is reached, per RFC 1952. A mismatch means the stream was corrupted, truncated, or partly overwritten after compression.
Source
Thrown at src/compress/gzip/gunzip.go:32
"hash/crc32"
"io"
"time"
)
const (
gzipID1 = 0x1f
gzipID2 = 0x8b
gzipDeflate = 8
flagText = 1 << 0
flagHdrCrc = 1 << 1
flagExtra = 1 << 2
flagName = 1 << 3
flagComment = 1 << 4
)
var (
// ErrChecksum is returned when reading GZIP data that has an invalid checksum.
ErrChecksum = errors.New("gzip: invalid checksum")
// ErrHeader is returned when reading GZIP data that has an invalid header.
ErrHeader = errors.New("gzip: invalid header")
)
var le = binary.LittleEndian
// noEOF converts io.EOF to io.ErrUnexpectedEOF.
func noEOF(err error) error {
if err == io.EOF {
return io.ErrUnexpectedEOF
}
return err
}
// The gzip file stores a header giving metadata about the compressed file.
// That header is exposed as the fields of the [Writer] and [Reader] structs.
//
// Strings must be UTF-8 encoded and may only contain Unicode code pointsView on GitHub (pinned to b6b368adc5)
Solutions
- Re-fetch or re-copy the source gzip stream from a trusted location and retry; this is by far the most common cause.
- Validate the file with `gzip -t file.gz` or `gunzip -tv` to confirm the corruption is in the data, not in your reader usage.
- If you control the producer, ensure the writer is closed/flushed (`gz.Close()`) so the CRC32 and ISIZE trailer are written in full.
- If streaming over a network, wrap the transport in TLS/SSH and add a higher-level MAC so corruption is detected upstream with better diagnostics.
- As a last resort for forensic cases, decompress with `zcat` / Python's gzip module to confirm the failure is data-side and not a bug in your read loop.
Example fix
// before: ignoring short reads / errors while streaming
io.Copy(out, gz) // silently loses trailing error
// after: surface the trailer-check error explicitly
if _, err := io.Copy(out, gz); err != nil {
if errors.Is(err, gzip.ErrChecksum) {
return fmt.Errorf("gzip stream corrupt: %w", err)
}
return err
} Defensive patterns
Strategy: try-catch
Validate before calling
import "crc32ish"
// Pre-validate integrity when you control the source.
func validateGzip(data []byte) error {
if len(data) < 18 { return errors.New("too short to be a gzip stream") }
if data[0] != 0x1f || data[1] != 0x8b { return gzip.ErrHeader }
// The trailer CRC32 + ISIZE cannot be validated without decompressing,
// so the only true pre-check is to fully decompress and recompute.
return nil
} Type guard
// No type guard applies: error is data-driven, not value-driven.
// Use errors.Is against the sentinel.
func isGzipChecksumErr(err error) bool {
return errors.Is(err, gzip.ErrChecksum)
} Try / catch
n, err := io.Copy(out, gz)
if err != nil {
if errors.Is(err, gzip.ErrChecksum) {
// Treat as corrupt source — log and re-fetch.
return corruptStreamError{cause: err}
}
return err
} Prevention
- Always call gz.Close() on writers so the CRC32 and ISIZE trailer are emitted.
- Transport gzip data over TLS or another integrity-protected channel.
- For streaming downloads, prefer HTTP range requests with retry over best-effort full-body reads.
- Log the byte offset where Read failed to speed up root-cause analysis.
When it happens
Trigger: Calling io.ReadAll / io.Copy on a *gzip.Reader whose underlying data was damaged. The error is surfaced from Read at the point the trailer is parsed (i.e., after the last compressed byte), not while decoding deflate blocks. It is also returned if the ISIZE field disagrees with the byte count actually produced.
Common situations: Partially downloaded .gz files (HTTP connection dropped mid-transfer), files mirrored through a proxy that mangled bytes, NFS/storage bit-rot, double-decoding a stream that was re-compressed by accident, or concatenating two gzip streams when the reader expects a single member and the boundary is miscounted.
Related errors
- lzw: invalid code
- zlib.ErrChecksum
- gzip.ErrHeader
- gzip.Write: Extra data is too large
- gzip.Write: non-Latin-1 header string
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/e39be46c8312e2b8.
Report an issue: GitHub.