grpc/grpc-java · error · ZipException
Not in GZIP format
Error message
Not in GZIP format
What it means
GzipInflatingBuffer decompresses gZIP-framed data and must first read the GZIP header, which starts with the magic bytes 0x1f8b. If the stream's first two bytes do not match GZIP_MAGIC, it throws java.util.zip.ZipException("Not in GZIP format"), meaning the payload is not gzip-compressed data despite being announced as such.
Source
Thrown at core/src/main/java/io/grpc/internal/GzipInflatingBuffer.java:323
break;
default:
throw new AssertionError("Invalid state: " + state);
}
}
// If we finished a gzip block, check if we have enough bytes to read another header
isStalled =
!madeProgress
|| (state == State.HEADER && gzipMetadataReader.readableBytes() < GZIP_HEADER_MIN_SIZE);
return bytesRead;
}
private boolean processHeader() throws ZipException {
if (gzipMetadataReader.readableBytes() < GZIP_HEADER_MIN_SIZE) {
return false;
}
if (gzipMetadataReader.readUnsignedShort() != GZIP_MAGIC) {
throw new ZipException("Not in GZIP format");
}
if (gzipMetadataReader.readUnsignedByte() != 8) {
throw new ZipException("Unsupported compression method");
}
gzipHeaderFlag = gzipMetadataReader.readUnsignedByte();
gzipMetadataReader.skipBytes(6 /* remaining header bytes */);
state = State.HEADER_EXTRA_LEN;
return true;
}
private boolean processHeaderExtraLen() {
if ((gzipHeaderFlag & HEADER_EXTRA_FLAG) != HEADER_EXTRA_FLAG) {
state = State.HEADER_NAME;
return true;
}
if (gzipMetadataReader.readableBytes() < UNSIGNED_SHORT_SIZE) {
return false;
}View on GitHub (pinned to 64daddc1f3)
Solutions
- Verify both peers agree on the compression encoding (grpc-encoding: gzip) and only send gzip when negotiated; otherwise send identity.
- Check for truncation/corruption (proxy buffering, content-length mismatch) that chops the gzip header bytes.
- Remove double-compression: if an interceptor already gzips payloads, don't also enable transport gzip.
- Catch ZipException on the decompression path and fall back to identity decoding when the magic bytes are missing.
Example fix
// before byte[] payload = plainBytes; // advertised as gzip // after byte[] payload = gzip(plainBytes); // actually compress before sending with grpc-encoding: gzip
Defensive patterns
Strategy: try-catch
Validate before calling
if (data.length < 2 || (data[0] & 0xff) != 0x1f || (data[1] & 0xff) != 0x8b) {
throw new IllegalArgumentException("payload is not gzip; grpc-encoding mismatch?");
} Type guard
boolean isGzip(byte[] b) { return b != null && b.length >= 2 && b[0] == 0x1f && b[1] == (byte) 0x8b; } Try / catch
try {
msg = gzipDecompressor.decompress(frame);
} catch (ZipException e) {
// treat as identity or fail the call with INTERNAL status
} Prevention
- Ensure gzip encoding is only negotiated when both peers support it.
- Check content-length and proxy configs for truncation.
- Avoid double-compression between interceptors and transport.
When it happens
Trigger: A message declared with the 'gzip' gRPC encoding is actually plain (identity) bytes, truncated, or double-wrapped in another container, so inflateBytes/processHeader reads a non-0x1f8b magic number at the start of the stream.
Common situations: Server/client encoding negotiation mismatch (content-coding says gzip but data is raw); corrupt or truncated response bodies; misconfigured compression interceptors or proxies; double-decompression where an outer layer already inflated the data.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- Unsupported compression method
- Corrupt GZIP header
- Inflater data format exception:
- Corrupt GZIP trailer
- No ALTS context information found
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/0a861b485b272912.
Report an issue: GitHub.