RustPython/RustPython · error · OSError

no matching local address with {family=} found

Error message

no matching local address with {family=} found

What it means

Raised as OSError inside BaseEventLoop._connect_sock during create_connection when a local_addr was supplied and resolved, but none of the resolved local addresses share the socket family of the remote address currently being tried (the for/else branch with no recorded bind exceptions). It means the bind loop found no usable local endpoint for that address family.

Source

Thrown at Lib/asyncio/base_events.py:1041

                    for lfamily, _, _, _, laddr in local_addr_infos:
                        # skip local addresses of different family
                        if lfamily != family:
                            continue
                        try:
                            sock.bind(laddr)
                            break
                        except OSError as exc:
                            msg = (
                                f'error while attempting to bind on '
                                f'address {laddr!r}: {str(exc).lower()}'
                            )
                            exc = OSError(exc.errno, msg)
                            my_exceptions.append(exc)
                    else:  # all bind attempts failed
                        if my_exceptions:
                            raise my_exceptions.pop()
                        else:
                            raise OSError(f"no matching local address with {family=} found")
                await self.sock_connect(sock, address)
                return sock
            except OSError as exc:
                my_exceptions.append(exc)
                raise
        except:
            if sock is not None:
                try:
                    sock.close()
                except OSError:
                    # An error when closing a newly created socket is
                    # not important, but it can overwrite more important
                    # non-OSError error. So ignore it.
                    pass
            raise
        finally:
            exceptions = my_exceptions = None

View on GitHub (pinned to aaeab4f754)

Solutions

  1. Drop local_addr entirely and let the OS pick the source address
  2. Make local_addr family-compatible: use ('::', 0) for IPv6 remotes, ('0.0.0.0', 0) for IPv4 remotes
  3. Pre-resolve the remote, then pick local_addr with socket.family matching addrinfo[0]

Example fix

# before
await loop.create_connection(proto, '2001:db8::1', 80, local_addr=('127.0.0.1', 0))

# after
infos = await loop.getaddrinfo('2001:db8::1', 80, type=socket.SOCK_STREAM)
local = ('::', 0) if infos[0][0] == socket.AF_INET6 else ('0.0.0.0', 0)
await loop.create_connection(proto, '2001:db8::1', 80, local_addr=local)
Defensive patterns

Strategy: validation

Validate before calling

infos = await loop.getaddrinfo(host, port, type=socket.SOCK_STREAM)
remote_family = infos[0][0]
local = ('::', 0) if remote_family == socket.AF_INET6 else ('0.0.0.0', 0)
await loop.create_connection(proto, host, port, local_addr=local)

Type guard

def local_addr_matches_family(local_addr, family) -> bool:
    if local_addr is None:
        return True
    host = local_addr[0]
    try:
        socket.inet_pton(family, host)
        return True
    except OSError:
        return False

Try / catch

try:
    tr, pr = await loop.create_connection(p, host, port, local_addr=la)
except OSError as e:
    if 'no matching local address' in str(e):
        log.error('local_addr %r has no address in family of %r', la, host)
        tr, pr = await loop.create_connection(p, host, port)  # retry unbound
    else:
        raise

Prevention

When it happens

Trigger: await loop.create_connection(proto, '2001:db8::1', 80, local_addr=('127.0.0.1', 0)) — IPv6 remote with IPv4-only local_addr; family=socket.AF_INET6 forced while local_addr resolves only to A records; dual-stack hosts where getaddrinfo for the local name returns only the other family.

Common situations: Hardcoding local_addr=('0.0.0.0', 0) or ('127.0.0.1', 0) for outbound multi-family connections; migrating a service to IPv6 while keeping an IPv4 bind address; DNS returning unexpected families for the local hostname.

Related errors


AI-assisted analysis of RustPython/RustPython@aaeab4f754 (2026-08-17). Data as JSON: /api/errors/45dcc593a6f71fe2. Report an issue: GitHub.