TooTallNate/Java-WebSocket · error · InvalidDataException
1008
1008
Error message
{message} What it means
During decompression of a permessage-deflate message, the inflater throws DataFormatException because the payload is not valid DEFLATE data. The extension wraps it in an InvalidDataException with close code 1008 (POLICY_VALIDATION), carrying the inflater's message (e.g. 'invalid distance too far back'), and the connection is closed.
Solutions
- Verify both endpoints correctly implement RFC 7692, including appending the empty deflate block (0x00 0x00 0xFF 0xFF) to the last fragment before inflating.
- Confirm the peer actually sends compressed payloads only when the permessage-deflate extension was negotiated; check the handshake's Sec-WebSocket-Extensions header.
- Check for proxies/middleware that alter or truncate frame payloads.
- Log the inflater's detail message (it's carried in the InvalidDataException) to pinpoint the deflate defect.
Example fix
// before: client sends raw uncompressed text after negotiating permessage-deflate
ws.send("plain text"); // peer's inflater fails
// after: use the library's send API so frames are compressed as negotiated
webSocket.send("plain text"); // library applies permessage-deflate correctly Defensive patterns
Strategy: try-catch
Validate before calling
// sanity-check the negotiated extensions before assuming compressed frames
String ext = request.getHeader("Sec-WebSocket-Extensions");
boolean deflateNegotiated = ext != null && ext.contains("permessage-deflate"); Try / catch
try {
byte[] data = decompressed(frame);
} catch (InvalidDataException e) {
// close code 1008, invalid deflate payload
logger.warn("deflate decode failed: {}", e.getMessage());
webSocket.close(1008, "invalid compressed payload");
} Prevention
- Ensure both ends implement RFC 7692 including the 0x00 0x00 0xFF 0xFF tail block
- Don't bypass the library's frame encoding when compression is negotiated
- Check proxies/intermediaries for payload mangling
When it happens
Trigger: decompress() is called (via decompressed()) and Inflater.inflate() throws DataFormatException — i.e. a frame payload claimed to be compressed (RSV1 set / negotiated permessage-deflate) is not valid zlib-deflate data or is missing the trailing 0x00 0x00 0xFF 0xFF empty block on the final fragment.
Common situations: Peers that claim permessage-deflate support but don't actually compress payloads; corruption by intermediaries/proxies; clients that forget the 4-byte tail block; double-decompression in custom code layered on the library.
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
- Continuous frame cannot have RSV1, RSV2 or RSV3 set
- bad rsv RSV1: RSV2: RSV3
- Inflated fragment size exceeds limit of
- 1007
- buffer size < 0
AI-assisted analysis of TooTallNate/Java-WebSocket@afeacbf8c0 (2026-09-09).
Data as JSON: /api/errors/e9b81eb177f835b4.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/org/java_websocket/extensions/permessage_deflate/PerMessageDeflateExtension.java:252
// RFC 7692: If the "agreed parameters" contain the "client|server_no_context_takeover"
// extension parameter, the server|client MAY decompress each new message with an empty
// LZ77 sliding window.
if (isDecompressorResetAllowed) {
decompressor.reset();
}
}
}
private byte[] decompress(ByteBuffer buffer, boolean isFinal) throws InvalidDataException {
ByteArrayOutputStream decompressed = new ByteArrayOutputStream();
try {
decompress(buffer, decompressed);
// RFC 7692: Append empty deflate block to the tail end of the payload of the message
if (isFinal) {
decompress(ByteBuffer.wrap(EMPTY_DEFLATE_BLOCK), decompressed);
}
} catch (DataFormatException e) {
throw new InvalidDataException(CloseFrame.POLICY_VALIDATION, e.getMessage());
}
return decompressed.toByteArray();
}
private void decompress(ByteBuffer buffer, ByteArrayOutputStream decompressed)
throws DataFormatException {
if (buffer.hasArray()) {
decompressor.setInput(
buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining());
} else {
byte[] input = new byte[buffer.remaining()];
buffer.duplicate().get(input);
decompressor.setInput(input);
}
byte[] chunk = new byte[TRANSFER_CHUNK_SIZE];
while (!decompressor.finished()) {
int length = decompressor.inflate(chunk);
if (length > 0) {View on GitHub (pinned to afeacbf8c0)