aio-libs/aiohttp · error · WSMessageTypeError
Received message {msg.type}:{msg.data!r} is not WSMsgType.BI
Error message
Received message {msg.type}:{msg.data!r} is not WSMsgType.BINARY What it means
Raised by ClientWebSocketResponse.receive_bytes() when the next message is not a BINARY frame. receive_bytes promises bytes, so a TEXT frame, a CLOSE/CLOSED control frame, or an ERROR frame makes the contract impossible to keep and aiohttp raises WSMessageTypeError (TypeError subclass). The offending type and data are included in the message for debugging.
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 c0ef574e29)
Solutions
- Switch to `msg = await ws.receive()` and branch on `msg.type == WSMsgType.BINARY`.
- Verify the server actually sends BINARY frames; the message shows the actual frame type received.
- Catch WSMessageTypeError around receive_bytes() to recover gracefully and treat it as a protocol error / connection end.
Example fix
// before
data = await ws.receive_bytes()
// after
from aiohttp import WSMsgType
msg = await ws.receive()
if msg.type == WSMsgType.BINARY:
data = msg.data
else:
raise RuntimeError(f"expected binary, got {msg.type}") Defensive patterns
Strategy: try-catch
Validate before calling
from aiohttp import WSMsgType
async def safe_receive_bytes(ws):
msg = await ws.receive()
if msg.type is not WSMsgType.BINARY:
raise WSMessageTypeError(f"expected BINARY, got {msg.type}")
return msg.data Type guard
from aiohttp import WSMsgType
from aiohttp.http_websocket import WSMessage
def is_binary_message(msg: WSMessage) -> bool:
return msg.type is WSMsgType.BINARY Try / catch
from aiohttp import WSMessageTypeError
try:
data = await ws.receive_bytes()
except WSMessageTypeError as e:
if ws.closed:
return None
raise Prevention
- Use ws.receive() and check WSMsgType.BINARY when the peer might send text or control frames.
- Stop calling receive_bytes() after observing CLOSED/ERROR.
- Negotiate subprotocol/encoding with the server up front so both sides agree on binary vs text.
When it happens
Trigger: Calling `await ws.receive_bytes()` when the peer sent a TEXT frame, or when the socket returned a CLOSE/ERROR/CLOSED control message.
Common situations: Server normally sends text but client assumed binary. Peer closed the connection mid-exchange. A protocol version mismatch where the server picks text framing. Using receive_bytes() after the connection has already started draining control frames.
Related errors
- Received message {msg.type}:{msg.data!r} is not WSMsgType.TE
- Invalid window size
- Extension for deflate not supported{ext}
- Invalid response status
- Invalid upgrade header
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/9055674310a7309b.json.
Report an issue: GitHub.