{"record":{"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/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/client_ws.py#L463-L499","documentation":"Raised by receive_str() when the message returned by receive() has a type other than WSMsgType.TEXT. receive_str() is a convenience that assumes the next frame is text; any other frame type (BINARY, PING, PONG, CLOSE, ERROR, or the synthetic CLOSED/CLOSING messages) trips the guard. WSMessageTypeError subclasses TypeError so it stands apart from transport errors.","triggerScenarios":"Server sends a BINARY frame while the client loops on receive_str(); server initiates a CLOSE and the client calls receive_str() after; a PING/PONG control frame is the next frame in the queue; an ERROR frame (e.g. decompression failure) is delivered.","commonSituations":"Protocol mismatch: server treats the channel as binary, client treats it as text; not draining control frames before expecting text; continuing to call receive_str() during teardown.","solutions":["Use the generic ws.receive() loop and branch on msg.type, only decoding when type is WSMsgType.TEXT.","If the server legitimately sends binary, switch to receive_bytes().","Guard the teardown: stop calling receive_str() after a CLOSE or CLOSED message.","Handle WSMessageTypeError explicitly so control frames do not crash the reader."],"exampleFix":"# before\nasync for _ in range(10):\n    text = await ws.receive_str()\n# after\nwhile True:\n    msg = await ws.receive()\n    if msg.type is WSMsgType.TEXT:\n        text = msg.data\n    elif msg.type in (WSMsgType.CLOSED, WSMsgType.CLOSE):\n        break","handlingStrategy":"validation","validationCode":"async def receive_text(ws, timeout=None):\n    msg = await ws.receive(timeout)\n    if msg.type is aiohttp.WSMsgType.TEXT:\n        return msg.data\n    if msg.type in (aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.CLOSE):\n        raise ConnectionResetError('websocket closed')\n    return None  # control frame; caller decides","typeGuard":"from aiohttp import WSMsgType\n\ndef is_text(msg) -> bool:\n    return msg.type is WSMsgType.TEXT","tryCatchPattern":"from aiohttp import WSMessageTypeError\ntry:\n    text = await ws.receive_str()\nexcept WSMessageTypeError as exc:\n    log.warning('non-text frame ignored: %s', exc)\n    text = None","preventionTips":["Drive a receive() loop and switch on msg.type rather than calling receive_str() blindly.","Treat CLOSE/CLOSED as a signal to stop reading.","Negotiate subprotocol type with the server up front so text/binary expectations match."],"tags":["websocket","client","message-type","receive-str"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}