aio-libs/aiohttp · error · ValueError
Compress wbits must between 9 and 15, zlib does not support
Error message
Compress wbits must between 9 and 15, zlib does not support wbits=8
What it means
ValueError raised by ws_ext_gen() when the 'compress' (window-bits) argument is outside the inclusive range 9-15. zlib does not support wbits=8 and values above 15 exceed the deflate spec, so the generator refuses to build an invalid Sec-WebSocket-Extensions offer. Unlike errors [1]/[2] this is a programming/config error on the local side, not a peer-handshake rejection.
Source
Thrown at aiohttp/_websocket/helpers.py:135
raise WSHandshakeError("Invalid window size")
if match.group(2):
notakeover = True
# Ignore regex group 5 & 6 for client_max_window_bits
break
# Return Fail if client side and not match
elif not isserver:
raise WSHandshakeError("Extension for deflate not supported" + ext.group(1))
return compress, notakeover
def ws_ext_gen(
compress: int = 15, isserver: bool = False, server_notakeover: bool = False
) -> str:
# client_notakeover=False not used for server
# compress wbit 8 does not support in zlib
if compress < 9 or compress > 15:
raise ValueError(
"Compress wbits must between 9 and 15, zlib does not support wbits=8"
)
enabledext = ["permessage-deflate"]
if not isserver:
enabledext.append("client_max_window_bits")
if compress < 15:
enabledext.append("server_max_window_bits=" + str(compress))
if server_notakeover:
enabledext.append("server_no_context_takeover")
# if client_notakeover:
# enabledext.append('client_no_context_takeover')
return "; ".join(enabledext)
View on GitHub (pinned to c0ef574e29)
Solutions
- Pass a compress value in 9-15, or simply use the default 15 / compress=True.
- Clamp the value before generating: compress = max(9, min(15, requested)).
- Do not conflate 'compress' (permessage-deflate window bits) with zlib compression level (1-9); use the correct parameter for each.
- If you genuinely need no compression, pass compress=0 / compress=False rather than an out-of-range integer.
Example fix
# before from aiohttp.http import ws_ext_gen hdr = ws_ext_gen(compress=8) # ValueError # after from aiohttp.http import ws_ext_gen hdr = ws_ext_gen(compress=9) # smallest legal window size
Defensive patterns
Strategy: validation
Validate before calling
from aiohttp.http import ws_ext_gen
def safe_ws_ext_gen(compress):
if compress == 0:
return ''
if not (9 <= compress <= 15):
raise ValueError(f'compress must be 9-15, got {compress}')
return ws_ext_gen(compress=compress) Prevention
- Always pass compress in the 9-15 range, or use the bool/15 default.
- Remember 'compress' is a window-bits value, not a zlib level (1-9).
- Use compress=0/False to disable, never an out-of-range integer.
When it happens
Trigger: Calling aiohttp.http.ws_ext_gen(compress=8) (or 7, 16, 0, negative) directly, or a code path that passes an out-of-range integer compress value into the extension-string generator. On the server, ws_ext_parse(isserver=True) clamps out-of-range client offers to 0 (so the public WebSocketResponse path normally shields you), so this is most often hit by direct ws_ext_gen callers or custom negotiation code.
Common situations: Custom WebSocket handshake code that forwards an unvalidated wbits value to ws_ext_gen; porting code that assumed wbits=8 was allowed; passing WebSocketResponse(compress=8) expecting it to mean 'compression level 8' (it is a window-bits value, not a level).
Related errors
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/7bcfb15342f0363d.json.
Report an issue: GitHub.