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 ClientWebSocketResponse.receive_str() when the next message pulled off the socket is not a TEXT frame. aiohttp guards the return type strictly because receive_str promises a str, so any other frame (BINARY, PING, PONG, CLOSE, or an ERROR/CLOSED control frame) violates that contract and surfaces as WSMessageTypeError (a TypeError subclass). The error string echoes the offending msg.type and msg.data so you can see exactly what the peer sent instead.

Source

Thrown at aiohttp/client_ws.py:481

    @overload
    async def receive_str(
        self: "ClientWebSocketResponse[Literal[False]]", *, timeout: float | None = None
    ) -> bytes: ...

    @overload
    async def receive_str(
        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,

View on GitHub (pinned to c0ef574e29)

Solutions

  1. Use `msg = await ws.receive()` and dispatch on `msg.type` (WSMsgType.TEXT/BINARY/CLOSED/ERROR) instead of unconditionally calling receive_str().
  2. If the peer should send text, check the server implementation; the bytes you received are shown in the message.
  3. Guard the call: only `await ws.receive_str()` inside a loop where you have already confirmed `ws.receive()` returned TEXT, or handle WSMessageTypeError explicitly.

Example fix

// before
msg = await ws.receive_str()
// after
from aiohttp import WSMsgType
msg = await ws.receive()
if msg.type == WSMsgType.TEXT:
    text = msg.data
elif msg.type in (WSMsgType.CLOSED, WSMsgType.ERROR):
    raise RuntimeError(f"ws closed: {msg}")
Defensive patterns

Strategy: try-catch

Validate before calling

from aiohttp import WSMsgType
async def safe_receive_str(ws):
    msg = await ws.receive()
    if msg.type is not WSMsgType.TEXT:
        raise WSMessageTypeError(f"expected TEXT, got {msg.type}")
    return msg.data

Type guard

from aiohttp import WSMsgType
from aiohttp.http_websocket import WSMessage

def is_text_message(msg: WSMessage) -> bool:
    return msg.type is WSMsgType.TEXT

Try / catch

from aiohttp import WSMessageTypeError
try:
    text = await ws.receive_str()
except WSMessageTypeError as e:
    # peer sent non-text (close/binary/error); decide whether to close or recover
    if ws.closed:
        return None
    raise

Prevention

When it happens

Trigger: Calling `await ws.receive_str()` when the server just sent a BINARY frame, a CLOSE frame (peer closed), or any control frame. Also when the connection is in CLOSING/CLOSED state and receive() returns a non-TEXT message.

Common situations: Talking to a WS server that sends binary payloads (protobuf, msgpack) while the client assumes text. The peer closing the connection mid-stream. Mixing receive() with receive_str() incorrectly. A buggy server sending the wrong frame opcode.

Related errors


AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04). Data as JSON: /data/errors/facd69ad8a633d2b.json. Report an issue: GitHub.