python/cpython · warning · TypeError

write() argument must be bytes-like, not {type(b).__name__}

Error message

write() argument must be bytes-like, not {type(b).__name__}

What it means

Debug-mode guard in BaseSelectorEventLoop.sock_recvfrom(): datagram receive via the loop requires a non-blocking socket, checked with gettimeout() != 0 whenever the loop is in debug mode. The check exists because the loop's readiness model assumes any recvfrom attempt can safely return EWOULDBLOCK instead of parking the whole thread.

Source

Thrown at Lib/_android_support.py:126

class BinaryLogStream(io.RawIOBase):
    def __init__(self, prio, tag, fileno=None):
        self.prio = prio
        self.tag = tag
        self._fileno = fileno

    def __repr__(self):
        return f"<BinaryLogStream {self.tag!r}>"

    def writable(self):
        return True

    def write(self, b):
        if type(b) is not bytes:
            try:
                b = bytes(memoryview(b))
            except TypeError:
                raise TypeError(
                    f"write() argument must be bytes-like, not {type(b).__name__}"
                ) from None

        # Writing an empty string to the stream should have no effect.
        if b:
            logcat.write(self.prio, self.tag, b)
        return len(b)

    # This is needed by the test suite --timeout option, which uses faulthandler.
    def fileno(self):
        if self._fileno is None:
            raise io.UnsupportedOperation("fileno")
        return self._fileno


# When a large volume of data is written to logcat at once, e.g. when a test
# module fails in --verbose3 mode, there's a risk of overflowing logcat's own
# buffer and losing messages. We avoid this by imposing a rate limit using the

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. sock.setblocking(False) immediately after creating the datagram socket
  2. Centralize socket creation for the loop in one factory that enforces non-blocking mode
  3. Keep blocking-timeout sockets away from sock_* APIs; use them only with synchronous or threaded I/O

Example fix

# before
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
await loop.sock_recvfrom(sock, 2048)  # debug: ValueError
# after
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setblocking(False)
await loop.sock_recvfrom(sock, 2048)
Defensive patterns

Strategy: validation

Validate before calling

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setblocking(False)               # before first await

async def reader():
    while True:
        data, addr = await loop.sock_recvfrom(sock, 65536)

Try / catch

try:
    await loop.sock_recvfrom(sock, n)
except ValueError as e:
    if 'non-blocking' in str(e):
        sock.setblocking(False)
        return await loop.sock_recvfrom(sock, n)
    raise

Prevention

When it happens

Trigger: await loop.sock_recvfrom(sock, bufsize) with debug mode on and a blocking socket or one carrying a nonzero timeout. Typical with UDP sockets created plainly (socket.socket(AF_INET, SOCK_DGRAM)) that never had setblocking(False) called.

Common situations: UDP services moved from a thread-per-socket design onto an event loop; sockets adopted from other libraries (dtls wrappers, monitoring agents) with timeouts set; CI running with asyncio debug fixtures enabled.

Related errors


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