aio-libs/aiohttp · warning · WebSocketError
1009
1009
Error message
Decompressed message exceeds size limit {max_msg_size} What it means
WebSocketError (1009 MESSAGE_TOO_BIG) raised after inflating a permessage-deflate message whose decompressed size exceeds self._max_msg_size. The decompressor is allowed one extra byte (max_msg_size+1) precisely so that any result longer than the limit is detectable; this guards against compression bombs. Surfaced in receive() as msg.type == WSMsgType.ERROR with msg.data.code == 1009.
Source
Thrown at aiohttp/_websocket/reader_c.py:257
# received.
if compressed:
if not self._decompressobj:
self._decompressobj = ZLibDecompressor(suppress_deflate_header=True)
# XXX: It's possible that the zlib backend (isal is known to
# do this, maybe others too?) will return max_length bytes,
# but internally buffer more data such that the payload is
# >max_length, so we return one extra byte and if we're able
# to do that, then the message is too big.
payload_merged = self._decompressobj.decompress_sync(
assembled_payload + WS_DEFLATE_TRAILING,
(
self._max_msg_size + 1
if self._max_msg_size
else self._max_msg_size
),
)
if self._max_msg_size and len(payload_merged) > self._max_msg_size:
raise WebSocketError(
WSCloseCode.MESSAGE_TOO_BIG,
f"Decompressed message exceeds size limit {self._max_msg_size}",
)
elif type(assembled_payload) is bytes:
payload_merged = assembled_payload
else:
payload_merged = bytes(assembled_payload)
size = len(payload_merged)
if opcode == OP_CODE_TEXT:
if self._decode_text:
try:
text = payload_merged.decode("utf-8")
except UnicodeDecodeError as exc:
raise WebSocketError(
WSCloseCode.INVALID_TEXT, "Invalid UTF-8 text message"
) from exc
View on GitHub (pinned to c0ef574e29)
Solutions
- Raise the limit if the message is legitimate: WebSocketResponse(max_msg_size=...) / session.ws_connect(url, max_msg_size=...).
- Reduce the payload size or page/chunk it on the sender side.
- Disable permessage-deflate (compress=0/False) if compression is not needed, removing the decompression-bomb surface.
- Treat 1009 in the receive loop as a recoverable 'too big' signal and reconnect/stream instead of receiving whole.
Example fix
# before ws = await session.ws_connect(url) # default 4 MiB, big compressed msg -> 1009 # after ws = await session.ws_connect(url, max_msg_size=16 * 1024 * 1024)
Defensive patterns
Strategy: validation
Validate before calling
# set the limit BEFORE connecting, sized to your largest legitimate message MAX = 16 * 1024 * 1024 ws = await session.ws_connect(url, max_msg_size=MAX)
Type guard
from aiohttp import WSMsgType
def is_message_too_big(msg) -> bool:
return msg.type is WSMsgType.ERROR and getattr(msg.data, 'code', None) == 1009 Try / catch
msg = await ws.receive()
if msg.type is aiohttp.WSMsgType.ERROR and msg.data.code == 1009:
log.info('decompressed message exceeded max_msg_size; reconnecting/streaming')
await ws.close() Prevention
- Size max_msg_size to your real largest decompressed message, not the default 4 MiB.
- Consider disabling permessage-deflate (compress=0) to remove the decompression-bomb surface.
- Treat 1009 as recoverable: switch to a chunked/streamed protocol instead of whole-message receives.
When it happens
Trigger: permessage-deflate is negotiated (compress != 0) and a peer sends a small compressed payload that expands past max_msg_size (default 4 MiB). The check at reader_c.py:256 fires after decompress_sync returns more than max_msg_size bytes.
Common situations: A legit large compressed message (e.g. a big JSON/image blob) hitting the default 4 MiB cap; a malicious zip-bomb peer; max_msg_size lowered for memory reasons and a routine message now trips it. The connection is torn down with code 1009.
Related errors
- 1009
- Invalid window size
- Extension for deflate not supported{ext}
- Compress wbits must between 9 and 15, zlib does not support
- 1002
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/0c12668b30b986c1.json.
Report an issue: GitHub.