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 WebSocketResponse.receive_bytes() as a WSMessageTypeError (a TypeError subclass) when the message returned by receive() is not WSMsgType.BINARY. receive_bytes() expects a binary frame; receiving a TEXT frame, or any control/closing frame, trips the guard. The %r formatting shows the offending frame type and data.
Solutions
- Use receive() and dispatch on msg.type so TEXT, BINARY, CLOSE, and ERROR are handled distinctly.
- Catch WSMessageTypeError and either switch to text handling or close with a type-mismatch code.
- Align the client to send BINARY frames (e.g. orjson.dumps which returns bytes).
Example fix
// before
payload = await ws.receive_bytes() # raises on text
// after
from aiohttp import WSMessageTypeError
try:
payload = await ws.receive_bytes()
except WSMessageTypeError:
msg = await ws.receive()
if msg.type == WSMsgType.TEXT:
payload = msg.data.encode('utf-8')
else:
raise
# or dispatch up front:
msg = await ws.receive()
if msg.type == WSMsgType.BINARY: ...
elif msg.type == WSMsgType.TEXT: ... Defensive patterns
Strategy: try-catch
Validate before calling
from aiohttp import WSMessageTypeError
try:
payload = await ws.receive_bytes()
except WSMessageTypeError:
msg = await ws.receive()
if msg.type == WSMsgType.BINARY:
payload = msg.data
else:
raise Type guard
def is_binary_msg(msg) -> bool:
return msg.type is WSMsgType.BINARY Try / catch
try:
payload = await ws.receive_bytes()
except WSMessageTypeError as e:
await ws.close(code=WSCloseCode.UNSUPPORTED_DATA, message=b'expected binary')
raise Prevention
- Use receive() with type dispatch for protocols that mix frame types.
- Ensure clients serialize to bytes (e.g. orjson.dumps) when the server reads binary.
- Catch WSMessageTypeError specifically rather than broad TypeError.
When it happens
Trigger: Peer sends a TEXT frame when the server calls receive_bytes(); a CLOSE/CLOSED frame arrives during a receive_bytes loop; the client serializes with json.dumps (str) but the server expects bytes.
Common situations: Mismatched framing between client (text JSON) and server (expecting binary); control frames interrupting a binary read loop; reusing receive_bytes when the protocol actually sends text.
Related errors
- Received message : is not WSMsgType.TEXT
- data argument must be byte-ish (%r)
- 1002
- 1007
- Concurrent call to receive() is not allowed
AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11).
Data as JSON: /api/errors/4a4a83ac04722223.
Report an issue: GitHub.
Appendix: source
Thrown at aiohttp/web_ws.py:701
self: "WebSocketResponse[_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: "WebSocketResponse[Literal[True]]",
*,
loads: JSONDecoder = ...,
timeout: float | None = None,
) -> Any: ...
@overload
async def receive_json(
self: "WebSocketResponse[Literal[False]]",
*,
loads: Callable[[bytes], Any] = ...,
timeout: float | None = None,View on GitHub (pinned to d041d4d0fd)