aio-libs/aiohttp · error · WSMessageTypeError
Received message {msg.type}:{msg.data!r} is not WSMsgType.TE
Error message
Received message {msg.type}:{msg.data!r} is not WSMsgType.TEXT What it means
Raised by WebSocketResponse.receive_str() as a WSMessageTypeError (a TypeError subclass) when the received message is not a TEXT frame. receive_str() calls receive() then asserts msg.type is WSMsgType.TEXT; a BINARY frame, or a control/close message returned by receive(), fails the check. The message includes the actual type and data for diagnostics.
Source
Thrown at aiohttp/web_ws.py:693
@overload
async def receive_str(
self: "WebSocketResponse[Literal[False]]", *, timeout: float | None = None
) -> bytes: ...
@overload
async def receive_str(
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,View on GitHub (pinned to c0ef574e29)
Solutions
- Use the generic receive() and branch on msg.type so you can handle BINARY and control frames.
- Check `msg.type` before treating data as text; only call receive_str() when you know the peer sends TEXT.
- Catch WSMessageTypeError (from aiohttp.client_exceptions) to recover when a non-text frame arrives.
- Coordinate the wire protocol with the peer so both sides agree on text vs binary.
Example fix
# before
async for _ in ws:
text = await ws.receive_str() # raises on BINARY/CLOSE
# after
async for msg in ws:
if msg.type == WSMsgType.TEXT:
handle_text(msg.data)
elif msg.type == WSMsgType.BINARY:
handle_binary(msg.data) Defensive patterns
Strategy: try-catch
Validate before calling
from aiohttp import WSMsgType
from aiohttp.client_exceptions import WSMessageTypeError
async def receive_text(ws):
msg = await ws.receive()
if msg.type is WSMsgType.TEXT:
return msg.data
return None Type guard
from aiohttp import WSMsgType
def is_text(msg) -> bool:
return msg.type is WSMsgType.TEXT Try / catch
from aiohttp.client_exceptions import WSMessageTypeError
try:
text = await ws.receive_str()
except WSMessageTypeError:
# peer sent a non-text frame; handle via generic receive()
msg = await ws.receive() Prevention
- Use generic receive() and branch on msg.type when the protocol mixes frame types.
- Catch WSMessageTypeError at boundaries where a non-text frame is recoverable.
- Agree on text vs binary with the peer up front.
When it happens
Trigger: Calling `await ws.receive_str()` when the peer sent a BINARY frame, or when receive() returned a CLOSE/CLOSING/CLOSED/PING/PONG control message. The check at aiohttp/web_ws.py:692-695 raises.
Common situations: Peer sends binary data but the server assumes text; mixing JSON-as-text and binary attachments on the same socket; receive_str() called after the connection started closing, so receive() returns a CLOSE sentinel; a client that switches frame types mid-stream.
Related errors
- Received message {msg.type}:{msg.data!r} is not WSMsgType.BI
- data argument must be byte-ish (%r)
- Concurrent call to receive() is not allowed
- WebSocket connection is closed.
- Compress wbits must between 9 and 15, zlib does not support
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/4d1621b6fee91575.json.
Report an issue: GitHub.