aio-libs/aiohttp · error · TypeError
data argument must be byte-ish (%r)
Error message
data argument must be byte-ish (%r)
What it means
Raised by WebSocketResponse.send_bytes() as a TypeError when the `data` argument is not one of bytes, bytearray, or memoryview. send_bytes encodes and transmits a BINARY frame, which must be raw bytes; passing a str (or int/None/dict) has no valid binary representation. The offending type is included in the message via %r.
Source
Thrown at aiohttp/web_ws.py:475
"""Send a frame over the websocket."""
if self._writer is None:
raise RuntimeError("Call .prepare() first")
await self._writer.send_frame(message, opcode, compress)
async def send_str(self, data: str, compress: int | None = None) -> None:
if self._writer is None:
raise RuntimeError("Call .prepare() first")
if not isinstance(data, str):
raise TypeError("data argument must be str (%r)" % type(data))
await self._writer.send_frame(
data.encode("utf-8"), WSMsgType.TEXT, compress=compress
)
async def send_bytes(self, data: bytes, compress: int | None = None) -> None:
if self._writer is None:
raise RuntimeError("Call .prepare() first")
if not isinstance(data, (bytes, bytearray, memoryview)):
raise TypeError("data argument must be byte-ish (%r)" % type(data))
await self._writer.send_frame(data, WSMsgType.BINARY, compress=compress)
async def send_json(
self,
data: Any,
compress: int | None = None,
*,
dumps: JSONEncoder = json.dumps,
) -> None:
await self.send_str(dumps(data), compress=compress)
async def send_json_bytes(
self,
data: Any,
compress: int | None = None,
*,
dumps: JSONBytesEncoder,
) -> None:View on GitHub (pinned to c0ef574e29)
Solutions
- Pass bytes: encode strings first, e.g. `await ws.send_bytes(value.encode('utf-8'))`.
- Use send_str() when you actually have text, or send_json() for JSON payloads.
- If using an encoder that returns bytes (e.g. orjson.dumps), use send_json_bytes() which routes to send_bytes correctly.
- Add a type guard so callers with mixed types route to the correct method.
Example fix
# before
await ws.send_bytes('hello')
# after
await ws.send_bytes(b'hello')
# or, for text:
await ws.send_str('hello') Defensive patterns
Strategy: type-guard
Validate before calling
from collections.abc import Buffer
def to_bytes(data) -> bytes:
if isinstance(data, (bytes, bytearray, memoryview)):
return bytes(data)
raise TypeError(f"expected byte-ish, got {type(data)!r}")
await ws.send_bytes(to_bytes(payload)) Type guard
def is_byteish(data) -> bool:
return isinstance(data, (bytes, bytearray, memoryview)) Try / catch
try:
await ws.send_bytes(data)
except TypeError as e:
if "byte-ish" in str(e):
await ws.send_bytes(str(data).encode())
else:
raise Prevention
- Encode strings before passing to send_bytes, or use send_str for text.
- Use send_json_bytes with a bytes-returning encoder for JSON.
- Add a type hint and a quick isinstance check at API boundaries.
When it happens
Trigger: Calling `await ws.send_bytes('text')` (passing a str), `ws.send_bytes(123)`, `ws.send_bytes(None)`, or any non-bytes value. The isinstance check at aiohttp/web_ws.py:474-475 fires after the prepare check.
Common situations: Mixing up send_str (for text) and send_bytes (for binary); passing a JSON string instead of using send_json; reading a file in text mode and forwarding the str; passing a serialised object that returns str from its encoder.
Related errors
- Received message {msg.type}:{msg.data!r} is not WSMsgType.TE
- Received message {msg.type}:{msg.data!r} is not WSMsgType.BI
- Compress wbits must between 9 and 15, zlib does not support
- 1007
- Response has not been started
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/4ae9130b44164b9f.json.
Report an issue: GitHub.