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

  1. Encode all payloads: transport.sendto(msg.encode('utf-8'), addr).
  2. Serialize explicitly before sending: transport.sendto(json.dumps(obj).encode(), addr) or struct.pack(...).
  3. 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

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


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/be52fdb2f1eee9e6. Report an issue: GitHub.