grpc/grpc-java · error · DataFormatException

Inflater data format exception:

Error message

Inflater data format exception: 

What it means

When the java.util.zip.Inflater rejects the deflate stream, inflate() catches the raw DataFormatException and rethrows a new DataFormatException prefixed with 'Inflater data format exception: ' so callers/tests can match on the prefix. It means the compressed data itself (after the gzip header) violates the DEFLATE format.

Source

Thrown at core/src/main/java/io/grpc/internal/GzipInflatingBuffer.java:437

      int bytesConsumedDelta = inflater.getTotalIn() - inflaterTotalIn;
      bytesConsumed += bytesConsumedDelta;
      deflatedBytesConsumed += bytesConsumedDelta;
      inflaterInputStart += bytesConsumedDelta;
      crc.update(b, off, n);

      if (inflater.finished()) {
        // Save bytes written to check against the trailer ISIZE
        expectedGzipTrailerIsize = (inflater.getBytesWritten() & 0xffffffffL);

        state = State.TRAILER;
      } else if (inflater.needsInput()) {
        state = State.INFLATER_NEEDS_INPUT;
      }

      return n;
    } catch (DataFormatException e) {
      // Wrap the exception so tests can check for a specific prefix
      throw new DataFormatException("Inflater data format exception: " + e.getMessage());
    }
  }

  private boolean fill() {
    checkState(inflater != null, "inflater is null");
    checkState(inflaterInputStart == inflaterInputEnd, "inflaterInput has unconsumed bytes");
    int bytesToAdd = Math.min(gzippedData.readableBytes(), INFLATE_BUFFER_SIZE);
    if (bytesToAdd == 0) {
      return false;
    }
    inflaterInputStart = 0;
    inflaterInputEnd = bytesToAdd;
    gzippedData.readBytes(inflaterInput, inflaterInputStart, bytesToAdd);
    inflater.setInput(inflaterInput, inflaterInputStart, bytesToAdd);
    state = State.INFLATING;
    return true;
  }

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Inspect the wrapped exception's message (getCause chain / prefix text) to identify the exact byte offset reported by the Inflater
  2. Re-capture the payload and validate with `gzip -dc`; if it fails, fix the sender or intermediary corrupting the body
  3. Ensure stream deadlines and flow control are not truncating large messages (tune maxInboundMessageSize, keepalive)
  4. Confirm both peers use standard gzip (the only method gRPC's gzip encoding defines)

Example fix

// before
try {
  stream.read(buffer);
} catch (StatusRuntimeException e) {
  // generic handling, data format detail lost
}
// after
try {
  stream.read(buffer);
} catch (StatusRuntimeException e) {
  if (e.getCause() instanceof DataFormatException
      && e.getCause().getMessage().startsWith("Inflater data format exception:")) {
    log.warn("Corrupt gzip body from peer", e); // reconnect / re-request
  } else {
    throw e;
  }
}
Defensive patterns

Strategy: try-catch

Try / catch

try { call(...); } catch (StatusRuntimeException e) {
  Throwable c = e.getCause();
  if (c instanceof DataFormatException && c.getMessage().startsWith("Inflater data format exception:")) {
    log.error("corrupt gzip body: {}", c.getMessage());
    // re-request or fall back to identity compression
  } else throw e;
}

Prevention

When it happens

Trigger: gzip header/trailer parse fine but the inflate() call on the body raises DataFormatException — e.g. non-deflate bytes between header and trailer, truncated deflate stream, or a stream produced with incompatible compression settings.

Common situations: Payload truncated by an idle-timeout or HTTP/2 flow-control bug; proxy stripping/replacing body bytes; wrong algorithm labeled as gzip (e.g. zstd, brotli); corrupted frames over flaky networks.

Understand the failure class

Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/458c28061583ea9b. Report an issue: GitHub.