Gzip output includes metadata as well as compressed content. Pass mtime=0 and an explicit compresslevel when comparing repeated gzip.compress calls, and scope byte reproducibility to the environment you actually tested.
Check the failure with a small fixture
A checksum changes although decompression yields identical data. Inspect container metadata and compressor settings.
import gzip, hashlib, sys, zlib
payload = b"repeatable fixture\n" * 30
first = gzip.compress(payload, compresslevel=6, mtime=1)
second = gzip.compress(payload, compresslevel=6, mtime=2)
assert first != second
assert gzip.decompress(first) == gzip.decompress(second) == payload
fixed_a = gzip.compress(payload, compresslevel=6, mtime=0)
fixed_b = gzip.compress(payload, compresslevel=6, mtime=0)
assert fixed_a == fixed_b
assert fixed_a[4:8] == b"\x00\x00\x00\x00"
print(sys.version.split()[0], zlib.ZLIB_RUNTIME_VERSION)
print(hashlib.sha256(fixed_a).hexdigest())What the result means
The first comparison changes only the timestamp and obtains different bytes for the same logical content. The second comparison fixes the timestamp and level within one runtime. This separates a metadata difference from damaged compressed data; always compare the decompressed payload before deciding that a changed checksum means corrupted content.
Choose the correction for your caller
Use explicit arguments rather than relying on defaults that changed across Python releases. gzip.compress gained mtime in Python 3.8; its default became 0 in 3.14, while the compression-level default changes in 3.15. The documented header OS-byte behavior also differs across releases. Record Python and zlib versions if byte-for-byte artifacts are part of your build contract. When using GzipFile instead, account for filename metadata as well as timestamps.
Limits and the next check
The assertions prove repeated output in the current process, not universal byte identity across Python, zlib or platform versions. If only logical content matters, hash the uncompressed bytes. If compressed bytes themselves are the artifact, pin and validate the complete build environment.
Related: Compare a related data or execution contract.
The embedded Python example was executed as an isolated local script on November 10, 2026 (KST), using Python 3.11.6. It demonstrates the stated boundary; it is not a test of your application or a promise of compatibility with every Python release.