python/cpython · error · ValueError

Invalid address: must be None or {self._address}

Error message

Invalid address: must be None or {self._address}

What it means

Raised by _SelectorDatagramTransport.sendto() as ValueError when the transport was created with a fixed remote address (remote_addr=... to create_datagram_endpoint, making it 'connected') and the caller supplies an addr that is neither None nor exactly that bound address. A connected UDP socket can only talk to its designated peer, so asyncio enforces the mismatch check.

Source

Thrown at Lib/asyncio/selector_events.py:1279

        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']:
                    self._sock.send(data)
                else:
                    self._sock.sendto(data, addr)
                return
            except (BlockingIOError, InterruptedError):

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. On a transport created with remote_addr, always send with addr=None (or the identical tuple) so it goes to the bound peer.
  2. If you must send to arbitrary destinations, create the endpoint WITHOUT remote_addr and pass the full address each sendto().
  3. Normalize addresses (resolve via socket.getaddrinfo) before comparing or storing the expected peer address.

Example fix

// before
transport, _ = await loop.create_datagram_endpoint(
    lambda: Proto(), remote_addr=('10.0.0.1', 9000))
transport.sendto(data, ('10.0.0.1', 9000))  # may fail if tuple form differs

// after
transport.sendto(data)  # addr=None -> bound remote_addr
# or, for many peers, omit remote_addr entirely:
# transport.sendto(data, peer_addr)
Defensive patterns

Strategy: validation

Validate before calling

# For a transport created with remote_addr, always send with addr=None:
transport.sendto(data)  # -> bound peer
# Or normalize before comparing:
import socket

def same_addr(a, b):
    ra = socket.getaddrinfo(*a[:2], type=socket.SOCK_DGRAM)[0][4]
    rb = socket.getaddrinfo(*b[:2], type=socket.SOCK_DGRAM)[0][4]
    return ra == rb

Try / catch

try:
    transport.sendto(data, addr)
except ValueError as e:
    if 'Invalid address' in str(e):
        transport.sendto(data)  # fall back to the bound remote address
    else:
        raise

Prevention

When it happens

Trigger: loop.create_datagram_endpoint(protocol, remote_addr=('10.0.0.1', 9000)) then transport.sendto(data, ('10.0.0.2', 9001)); the address comparison is exact, so even an equal-meaning tuple that differs in form fails.

Common situations: A UDP client written to reply to the address a datagram arrived from (addr from datagram_received) instead of passing None; reusing a connected-transport code path for multiple peers; address normalization differences (e.g. '127.0.0.1' vs hostname resolution result) causing tuple mismatch.

Related errors


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