aio-libs/aiohttp · error · WSMessageTypeError
Received message : is not WSMsgType.BINARY
Error message
Received message {msg.type}:{msg.data!r} is not WSMsgType.BINARY What it means
Raised by receive_bytes() when the next message is not WSMsgType.BINARY. It is the binary counterpart of error 82: receive_bytes() assumes the next frame is BINARY and rejects TEXT, CLOSE, PING, PONG, or ERROR frames with WSMessageTypeError.
Solutions
- Drive a ws.receive() loop and branch on msg.type before decoding.
- If text frames are legitimate, call receive_str() for those or fall back to receive().
- Break the loop cleanly on CLOSE/CLOSED instead of calling receive_bytes() again.
- Catch WSMessageTypeError to survive unexpected text frames during binary streaming.
Example fix
# before
async for _ in range(10):
payload = await ws.receive_bytes()
# after
while True:
msg = await ws.receive()
if msg.type is WSMsgType.BINARY:
payload = msg.data
elif msg.type is WSMsgType.TEXT:
log.warning('unexpected text: %r', msg.data)
elif msg.type in (WSMsgType.CLOSED, WSMsgType.CLOSE):
break Defensive patterns
Strategy: validation
Validate before calling
async def receive_binary(ws, timeout=None):
msg = await ws.receive(timeout)
if msg.type is aiohttp.WSMsgType.BINARY:
return msg.data
if msg.type in (aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.CLOSE):
raise ConnectionResetError('websocket closed')
return None Type guard
from aiohttp import WSMsgType
def is_binary(msg) -> bool:
return msg.type is WSMsgType.BINARY Try / catch
from aiohttp import WSMessageTypeError
try:
payload = await ws.receive_bytes()
except WSMessageTypeError as exc:
log.warning('non-binary frame ignored: %s', exc)
payload = b'' Prevention
- Use a receive() loop and branch on msg.type for mixed-protocol servers.
- Confirm the server's contract: pure-binary vs mixed before assuming receive_bytes() always works.
- Stop calling receive_bytes() once a CLOSE frame has been observed.
When it happens
Trigger: Server sends a TEXT frame (e.g. an error string) while client loops on receive_bytes(); a CLOSE frame arrives mid-stream; PING/PONG control frames are queued ahead of the next binary payload.
Common situations: Mixed-protocol servers that interleave text status messages with binary data; client assuming pure-binary when the server sends a textual handshake/error; teardown ordering.
Related errors
- Received message : is not WSMsgType.TEXT
- 1002
- Concurrent call to receive() is not allowed
- data argument must be byte-ish (%r)
- data argument must be str (%r)
AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11).
Data as JSON: /api/errors/9055674310a7309b.
Report an issue: GitHub.
Appendix: source
Thrown at aiohttp/client_ws.py:489
self: "ClientWebSocketResponse[_DecodeText]", *, timeout: float | None = None
) -> str | bytes: ...
async def receive_str(self, *, timeout: float | None = None) -> str | bytes:
"""Receive TEXT message.
Returns str when decode_text=True (default), bytes when decode_text=False.
"""
msg = await self.receive(timeout)
if msg.type is not WSMsgType.TEXT:
raise WSMessageTypeError(
f"Received message {msg.type}:{msg.data!r} is not WSMsgType.TEXT"
)
return msg.data
async def receive_bytes(self, *, timeout: float | None = None) -> bytes:
msg = await self.receive(timeout)
if msg.type is not WSMsgType.BINARY:
raise WSMessageTypeError(
f"Received message {msg.type}:{msg.data!r} is not WSMsgType.BINARY"
)
return msg.data
@overload
async def receive_json(
self: "ClientWebSocketResponse[Literal[True]]",
*,
loads: JSONDecoder = ...,
timeout: float | None = None,
) -> Any: ...
@overload
async def receive_json(
self: "ClientWebSocketResponse[Literal[False]]",
*,
loads: Callable[[bytes], Any] = ...,
timeout: float | None = None,View on GitHub (pinned to d041d4d0fd)