{"record":{"id":"ddeebf4dde8485a9","repo":"grpc/grpc-java","slug":"corrupt-gzip-header","errorCode":null,"errorMessage":"Corrupt GZIP header","messagePattern":"Corrupt GZIP header","errorType":"exception","errorClass":"ZipException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/grpc/internal/GzipInflatingBuffer.java","lineNumber":390,"sourceCode":"    }\n    if (!gzipMetadataReader.readBytesUntilZero()) {\n      return false;\n    }\n    state = State.HEADER_CRC;\n    return true;\n  }\n\n  private boolean processHeaderCrc() throws ZipException {\n    if ((gzipHeaderFlag & HEADER_CRC_FLAG) != HEADER_CRC_FLAG) {\n      state = State.INITIALIZE_INFLATER;\n      return true;\n    }\n    if (gzipMetadataReader.readableBytes() < UNSIGNED_SHORT_SIZE) {\n      return false;\n    }\n    int desiredCrc16 = (int) crc.getValue() & 0xffff;\n    if (desiredCrc16 != gzipMetadataReader.readUnsignedShort()) {\n      throw new ZipException(\"Corrupt GZIP header\");\n    }\n    state = State.INITIALIZE_INFLATER;\n    return true;\n  }\n\n  private boolean initializeInflater() {\n    if (inflater == null) {\n      inflater = new Inflater(true);\n    } else {\n      inflater.reset();\n    }\n    crc.reset();\n    int bytesRemainingInInflaterInput = inflaterInputEnd - inflaterInputStart;\n    if (bytesRemainingInInflaterInput > 0) {\n      inflater.setInput(inflaterInput, inflaterInputStart, bytesRemainingInInflaterInput);\n      state = State.INFLATING;\n    } else {\n      state = State.INFLATER_NEEDS_INPUT;","sourceCodeStart":372,"sourceCodeEnd":408,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/core/src/main/java/io/grpc/internal/GzipInflatingBuffer.java#L372-L408","documentation":"RFC 1952 optionally ends the gzip header with a CRC16 of the header bytes plus the FLG byte. processHeaderCrc compares the stored CRC16 against one it computes while reading the header. A mismatch means the header bytes were altered between write and read, so a ZipException('Corrupt GZIP header') is thrown.","triggerScenarios":"A gzip member whose header sets the FHCBC flag (header checksum present) but whose stored CRC16 does not match the CRC computed over the bytes actually received — corruption, truncation, or rewriting of the header.","commonSituations":"Middleboxes or service meshes rewriting headers (e.g. injecting bytes); corrupted cache entries; partial reads from an interrupted stream; hand-crafted gzip payloads built with a wrong CRC.","solutions":["Capture the raw bytes and run `gzip -t` to confirm corruption is upstream of the client","Disable intermediaries that rewrite the body (compression-aware proxies, WAFs) or mark the stream unbufferable","Regenerate the payload with a standard gzip implementation (GZIPOutputStream / `gzip`) instead of hand-rolled header construction","Retry the request over a clean connection in case of transient corruption"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// CRC16 check before consuming the stream is impractical client-side; verify offline:\n// gzip -t payload.gz && echo OK","typeGuard":null,"tryCatchPattern":"try { call(...); } catch (StatusRuntimeException e) {\n  if (e.getCause() instanceof ZipException && e.getCause().getMessage().contains(\"Corrupt GZIP header\")) {\n    return retryWithFreshConnection(request); // transient corruption\n  } throw e;\n}","preventionTips":["Avoid intermediaries that re-encode or rewrite response bodies","Serve gzip bodies over TLS so integrity violations are detected at the transport layer","Generate payloads only with standard gzip implementations"],"tags":["grpc","gzip","checksum","data-corruption"],"backgroundTag":"checksum-mismatch","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}