python/cpython · error · TypeError
data argument must be a bytes-like object, not {type(data)._
Error message
data argument must be a bytes-like object, not {type(data).__name__!r} What it means
Raised by _SelectorDatagramTransport.sendto() as TypeError when the data argument is not bytes, bytearray, or memoryview. Datagram transports exchange raw binary payloads only; strings and other sequence types are rejected at the boundary rather than encoded implicitly.
Source
Thrown at Lib/asyncio/selector_events.py:1274
def _read_ready(self):
if self._conn_lost:
return
try:
data, addr = self._sock.recvfrom(self.max_size)
except (BlockingIOError, InterruptedError):
pass
except OSError as exc:
self._protocol.error_received(exc)
except (SystemExit, KeyboardInterrupt):
raise
except BaseException as exc:
self._fatal_error(exc, 'Fatal read error on datagram transport')
else:
self._protocol.datagram_received(data, addr)
def sendto(self, data, addr=None):
if not isinstance(data, (bytes, bytearray, memoryview)):
raise TypeError(f'data argument must be a bytes-like object, '
f'not {type(data).__name__!r}')
if self._address:
if addr not in (None, self._address):
raise ValueError(
f'Invalid address: must be None or {self._address}')
addr = self._address
if self._conn_lost and self._address:
if self._conn_lost >= constants.LOG_THRESHOLD_FOR_CONNLOST_WRITES:
logger.warning('socket.send() raised exception.')
self._conn_lost += 1
return
if not self._buffer:
# Attempt to send it right away first.
try:
if self._extra['peername']:View on GitHub (pinned to bc6749cc3b)
Solutions
- Encode all payloads: transport.sendto(msg.encode('utf-8'), addr).
- Serialize explicitly before sending: transport.sendto(json.dumps(obj).encode(), addr) or struct.pack(...).
- Centralize encoding in a small send helper that type-checks before calling sendto().
Example fix
// before
transport.sendto(json.dumps({"cmd": "ping"}), addr) # str -> TypeError
// after
transport.sendto(json.dumps({"cmd": "ping"}).encode(), addr) Defensive patterns
Strategy: type-guard
Validate before calling
def udp_payload(data):
if isinstance(data, str):
return data.encode('utf-8')
if not isinstance(data, (bytes, bytearray, memoryview)):
raise TypeError(f'cannot send {type(data).__name__} as datagram')
return data
transport.sendto(udp_payload(msg), addr) Type guard
BytesLike = (bytes, bytearray, memoryview)
def is_datagram_payload(data) -> bool:
return isinstance(data, BytesLike) Try / catch
try:
transport.sendto(data, addr)
except TypeError as e:
if 'bytes-like' in str(e):
transport.sendto(str(data).encode(), addr)
else:
raise Prevention
- Encode to bytes before building datagrams; keep payloads bytes end-to-end.
- Annotate send helpers with `data: bytes` and check with mypy.
- Remember str is never implicitly encoded by asyncio transports.
When it happens
Trigger: transport.sendto('hello', addr) or protocol-level code calling the datagram transport's sendto() with a str, int, list, or custom object; reached via DatagramProtocol through loop.create_datagram_endpoint().
Common situations: Porting UDP code from a framework whose send() accepted str (e.g. some websocket/ZMQ wrappers); forgetting json.dumps(...).encode() when sending JSON datagrams; passing a pre-serialized object that is not yet bytes.
Related errors
- Invalid address: must be None or {self._address}
- Not implemented
- Unimplemented ioctl request
- A datagram socket was expected, got {sock!r}
- socket modifier keyword arguments can not be used when sock
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/be52fdb2f1eee9e6.
Report an issue: GitHub.