{"record":{"id":"aa93cabc12756f71","repo":"aio-libs/aiohttp","slug":"data-argument-must-be-str-r-aa93ca","errorCode":null,"errorMessage":"data argument must be str (%r)","messagePattern":"data argument must be str \\(%r\\)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"aiohttp/web_ws.py","lineNumber":466,"sourceCode":"    async def pong(self, message: bytes = b\"\") -> None:\n        # unsolicited pong\n        if self._writer is None:\n            raise RuntimeError(\"Call .prepare() first\")\n        await self._writer.send_frame(message, WSMsgType.PONG)\n\n    async def send_frame(\n        self, message: bytes, opcode: WSMsgType, compress: int | None = None\n    ) -> None:\n        \"\"\"Send a frame over the websocket.\"\"\"\n        if self._writer is None:\n            raise RuntimeError(\"Call .prepare() first\")\n        await self._writer.send_frame(message, opcode, compress)\n\n    async def send_str(self, data: str, compress: int | None = None) -> None:\n        if self._writer is None:\n            raise RuntimeError(\"Call .prepare() first\")\n        if not isinstance(data, str):\n            raise TypeError(\"data argument must be str (%r)\" % type(data))\n        await self._writer.send_frame(\n            data.encode(\"utf-8\"), WSMsgType.TEXT, compress=compress\n        )\n\n    async def send_bytes(self, data: bytes, compress: int | None = None) -> None:\n        if self._writer is None:\n            raise RuntimeError(\"Call .prepare() first\")\n        if not isinstance(data, (bytes, bytearray, memoryview)):\n            raise TypeError(\"data argument must be byte-ish (%r)\" % type(data))\n        await self._writer.send_frame(data, WSMsgType.BINARY, compress=compress)\n\n    async def send_json(\n        self,\n        data: Any,\n        compress: int | None = None,\n        *,\n        dumps: JSONEncoder = json.dumps,\n    ) -> None:","sourceCodeStart":448,"sourceCodeEnd":484,"githubUrl":"https://github.com/aio-libs/aiohttp/blob/d041d4d0fd48c3f0832084d33be16cf1c4835f85/aiohttp/web_ws.py#L448-L484","documentation":"WebSocketResponse.send_str() raises TypeError if the data argument is not a str — it must be encoded to UTF-8 before being sent as a TEXT frame. This check runs after the prepare() guard (error 278), so it only fires when the writer exists. Use send_bytes() for bytes/bytearray/memoryview (BINARY frames), or send_str(str(data)) to coerce.","triggerScenarios":"Calling await ws.send_str(42) (int), ws.send_str(b'hi') (bytes — should be send_bytes), ws.send_str({'k': 1}) (dict — should be send_json), ws.send_str(None).","commonSituations":"Passing JSON-serialised data without calling json.dumps first (sending a dict directly); passing bytes that should be a binary frame; passing numbers/bools from loosely-typed code; forgetting to coerce config values.","solutions":["Coerce to str first: await ws.send_str(str(value)) or json.dumps(value) for JSON payloads.","For raw bytes, use ws.send_bytes(data) (sends a BINARY frame).","For JSON, use ws.send_json(obj) which handles serialisation."],"exampleFix":"// before\nawait ws.send_str({'event': 'open'})  # TypeError: dict is not str\nawait ws.send_str(b'raw')               # TypeError: bytes is not str\n// after\nawait ws.send_json({'event': 'open'})\nawait ws.send_bytes(b'raw')","handlingStrategy":"type-guard","validationCode":"async def send_text(ws, value):\n    if not isinstance(value, str):\n        value = str(value)\n    await ws.send_str(value)","typeGuard":"def is_str_payload(value) -> bool:\n    return isinstance(value, str)","tryCatchPattern":"try:\n    await ws.send_str(payload)\nexcept TypeError as e:\n    if 'must be str' in str(e):\n        if isinstance(payload, (bytes, bytearray, memoryview)):\n            await ws.send_bytes(payload)\n        else:\n            await ws.send_json(payload)\n    else:\n        raise","preventionTips":["Use send_json(obj) for structured data, send_bytes(b'...') for binary, send_str('...') for text.","Coerce with str(value) or json.dumps(value) before send_str.","Run mypy on handler code — it catches non-str arguments to send_str."],"tags":["websocket","send-str","type-error","validation"],"backgroundTag":null,"analyzedSha":"d041d4d0fd48c3f0832084d33be16cf1c4835f85","analyzedAt":"2026-08-11T20:44:15.550Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}