{"id":"facd69ad8a633d2b","repo":"aio-libs/aiohttp","slug":"received-message-msg-type-msg-data-r-is-not-ws","errorCode":null,"errorMessage":"Received message {msg.type}:{msg.data!r} is not WSMsgType.TEXT","messagePattern":"Received message (.+?):(.+?) is not WSMsgType\\.TEXT","errorType":"exception","errorClass":"WSMessageTypeError","httpStatus":null,"severity":"error","filePath":"aiohttp/client_ws.py","lineNumber":481,"sourceCode":"\n    @overload\n    async def receive_str(\n        self: \"ClientWebSocketResponse[Literal[False]]\", *, timeout: float | None = None\n    ) -> bytes: ...\n\n    @overload\n    async def receive_str(\n        self: \"ClientWebSocketResponse[_DecodeText]\", *, timeout: float | None = None\n    ) -> str | bytes: ...\n\n    async def receive_str(self, *, timeout: float | None = None) -> str | bytes:\n        \"\"\"Receive TEXT message.\n\n        Returns str when decode_text=True (default), bytes when decode_text=False.\n        \"\"\"\n        msg = await self.receive(timeout)\n        if msg.type is not WSMsgType.TEXT:\n            raise WSMessageTypeError(\n                f\"Received message {msg.type}:{msg.data!r} is not WSMsgType.TEXT\"\n            )\n        return msg.data\n\n    async def receive_bytes(self, *, timeout: float | None = None) -> bytes:\n        msg = await self.receive(timeout)\n        if msg.type is not WSMsgType.BINARY:\n            raise WSMessageTypeError(\n                f\"Received message {msg.type}:{msg.data!r} is not WSMsgType.BINARY\"\n            )\n        return msg.data\n\n    @overload\n    async def receive_json(\n        self: \"ClientWebSocketResponse[Literal[True]]\",\n        *,\n        loads: JSONDecoder = ...,\n        timeout: float | None = None,","sourceCodeStart":463,"sourceCodeEnd":499,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/c0ef574e29109210e96e652771ae4e7b88615fa4/aiohttp/client_ws.py#L463-L499","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use `msg = await ws.receive()` and dispatch on `msg.type` (WSMsgType.TEXT/BINARY/CLOSED/ERROR) instead of unconditionally calling receive_str().","If the peer should send text, check the server implementation; the bytes you received are shown in the message.","Guard the call: only `await ws.receive_str()` inside a loop where you have already confirmed `ws.receive()` returned TEXT, or handle WSMessageTypeError explicitly."],"exampleFix":"// before\nmsg = await ws.receive_str()\n// after\nfrom aiohttp import WSMsgType\nmsg = await ws.receive()\nif msg.type == WSMsgType.TEXT:\n    text = msg.data\nelif msg.type in (WSMsgType.CLOSED, WSMsgType.ERROR):\n    raise RuntimeError(f\"ws closed: {msg}\")","handlingStrategy":"try-catch","validationCode":"from aiohttp import WSMsgType\nasync def safe_receive_str(ws):\n    msg = await ws.receive()\n    if msg.type is not WSMsgType.TEXT:\n        raise WSMessageTypeError(f\"expected TEXT, got {msg.type}\")\n    return msg.data","typeGuard":"from aiohttp import WSMsgType\nfrom aiohttp.http_websocket import WSMessage\n\ndef is_text_message(msg: WSMessage) -> bool:\n    return msg.type is WSMsgType.TEXT","tryCatchPattern":"from aiohttp import WSMessageTypeError\ntry:\n    text = await ws.receive_str()\nexcept WSMessageTypeError as e:\n    # peer sent non-text (close/binary/error); decide whether to close or recover\n    if ws.closed:\n        return None\n    raise","preventionTips":["Prefer the generic ws.receive() loop and branch on msg.type rather than receive_str() when the peer may send mixed frames.","Treat CLOSED/ERROR as terminal and stop calling receive_str() after them.","Document the expected frame type with the server team so the contract is explicit."],"tags":["websocket","client","message-type","receive"],"analyzedSha":"c0ef574e29109210e96e652771ae4e7b88615fa4","analyzedAt":"2026-08-04T19:51:05.467Z","schemaVersion":2}