{"record":{"id":"a2df6f5338b11972","repo":"aio-libs/aiohttp","slug":"wsclosecode-invalid-text","errorCode":"WSCloseCode.INVALID_TEXT","errorMessage":"Invalid UTF-8 text message","messagePattern":"Invalid UTF-8 text message","errorType":"exception","errorClass":"WebSocketError","httpStatus":null,"severity":"error","filePath":"aiohttp/_websocket/reader_py.py","lineNumber":272,"sourceCode":"                    ),\n                )\n                if self._max_msg_size and len(payload_merged) > self._max_msg_size:\n                    raise WebSocketError(\n                        WSCloseCode.MESSAGE_TOO_BIG,\n                        f\"Decompressed message exceeds size limit {self._max_msg_size}\",\n                    )\n            elif type(assembled_payload) is bytes:\n                payload_merged = assembled_payload\n            else:\n                payload_merged = bytes(assembled_payload)\n\n            size = len(payload_merged)\n            if opcode == OP_CODE_TEXT:\n                if self._decode_text:\n                    try:\n                        text = payload_merged.decode(\"utf-8\")\n                    except UnicodeDecodeError as exc:\n                        raise WebSocketError(\n                            WSCloseCode.INVALID_TEXT, \"Invalid UTF-8 text message\"\n                        ) from exc\n\n                    # XXX: The Text and Binary messages here can be a performance\n                    # bottleneck, so we use tuple.__new__ to improve performance.\n                    # This is not type safe, but many tests should fail in\n                    # test_client_ws_functional.py if this is wrong.\n                    msg = TUPLE_NEW(WSMessageText, (text, size, \"\", WS_MSG_TYPE_TEXT))\n                else:\n                    # Return raw bytes for TEXT messages when decode_text=False\n                    msg = TUPLE_NEW(\n                        WSMessageTextBytes, (payload_merged, size, \"\", WS_MSG_TYPE_TEXT)\n                    )\n            else:\n                msg = TUPLE_NEW(\n                    WSMessageBinary, (payload_merged, size, \"\", WS_MSG_TYPE_BINARY)\n                )\n","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d9aaf697c2cd4783ca5749a971965c689f3ec24f/aiohttp/_websocket/reader_py.py#L254-L290","documentation":"Raised as WebSocketError(INVALID_TEXT, code 1007) at reader_py.py:272 when a fully-assembled TEXT frame's payload cannot be decoded as UTF-8 (payload_merged.decode('utf-8') raises UnicodeDecodeError). This enforces the RFC 6455 requirement that text frames contain valid UTF-8. Only reached when self._decode_text is True (the default).","triggerScenarios":"The remote peer sends a text (opcode 0x1) frame whose assembled payload is not valid UTF-8, e.g. raw binary mislabelled as text, truncated multi-byte sequences, or mixed encodings. Delivered as WSMsgType.ERROR and closes the connection with code 1007.","commonSituations":"Peer sending bytes/ binary data on a text frame instead of using a binary frame; a producer that concatenates partial UTF-8 chunks across non-spec fragments; legacy/buggy client; a transcoding proxy corrupting bytes.","solutions":["Have the peer send non-text data on a binary (opcode 0x2) frame via `ws.send_bytes(data)`.","If you must tolerate invalid UTF-8, construct WebSocketResponse / ClientWebSocketResponse with autoping=True and handle WSMsgType.ERROR by closing and reconnecting.","On the receiver, check `msg.type == WSMsgType.ERROR` and inspect `msg.data.code == WSCloseCode.INVALID_TEXT` to report a clear upstream bug."],"exampleFix":"// before (peer side)\nawait ws.send_str(binary_payload)  # sent as text, may be non-UTF-8\n\n# after (peer side)\nawait ws.send_bytes(binary_payload)  # sent as a binary frame","handlingStrategy":"try-catch","validationCode":"# on the SENDER side, ensure text frames carry UTF-8\npayload = data.encode('utf-8') if isinstance(data, str) else data\nif isinstance(data, (bytes, bytearray)):\n    await ws.send_bytes(data)   # binary frame - safe for non-UTF-8\nelse:\n    await ws.send_str(data)     # text frame - must be valid UTF-8","typeGuard":"def is_valid_utf8_text(data: object) -> bool:\n    if isinstance(data, str):\n        return True\n    if isinstance(data, (bytes, bytearray)):\n        try:\n            data.decode('utf-8'); return True\n        except UnicodeDecodeError:\n            return False\n    return False","tryCatchPattern":"msg = await ws.receive()\nif msg.type == aiohttp.WSMsgType.ERROR and msg.data.code == aiohttp.WSCloseCode.INVALID_TEXT:\n    await ws.close()\n    # peer sent non-UTF-8 on a text frame; report upstream bug","preventionTips":["Send raw bytes with ws.send_bytes (binary frame), never ws.send_str, to avoid UTF-8 enforcement.","If decode_text is unnecessary, you may construct the WebSocket with parameters that keep bytes, but still validate the peer.","Always handle WSMsgType.ERROR + INVALID_TEXT so the connection closes cleanly."],"tags":["websocket","encoding","utf-8","text","protocol","rfc6455"],"analyzedSha":"d9aaf697c2cd4783ca5749a971965c689f3ec24f","analyzedAt":"2026-08-06T21:30:48.638Z","schemaVersion":2},"datasetVersion":"2026-08-07T01:17:05.418Z"}