python/cpython · error · OSError

Multiple exceptions

Error message

Multiple exceptions: {}

What it means

An OSError raised by create_connection (all_errors=False path) when multiple addresses were tried and all failed with different error strings. asyncio first tries to re-raise a single exception if there was only one attempt or all messages are identical; when they differ, it joins them into one OSError whose message is 'Multiple exceptions: ...' so the user can see every failure reason.

Solutions

  1. Parse or log the full message to see each underlying failure and fix the dominant one (often the first).
  2. Pass all_errors=True to get a structured ExceptionGroup instead of a string-joined message.
  3. Retry with backoff for transient network conditions once causes are known.

Example fix

// before
try:
    await loop.create_connection(proto, host, port)
except OSError as e:
    print(e)  # opaque 'Multiple exceptions: ...'

// after
try:
    await loop.create_connection(proto, host, port, all_errors=True)
except* OSError as eg:
    for exc in eg.exceptions:
        print(repr(exc))  # individual causes
Defensive patterns

Strategy: try-catch

Try / catch

try:
    tp, pr = await loop.create_connection(proto, host, port, all_errors=False)
except OSError as e:
    if str(e).startswith('Multiple exceptions:'):
        for part in str(e).split(', '):
            log.warning(f'connect failure: {part}')
    raise

Prevention

When it happens

Trigger: Connecting to a dual-stack host where the IPv6 attempt times out and the IPv4 attempt gets 'connection refused' — two distinct messages, so the combined OSError is raised. Only reachable with all_errors=False (pre-3.12 default).

Common situations: Partial reachability (v6 blocked, v4 refused), mixed DNS/timeout failures across multiple A records, flaky uplinks during address iteration.

Related errors


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

Appendix: source

Thrown at Lib/asyncio/base_events.py:1182

                    happy_eyeballs_delay,
                    loop=self,
                ))[0]  # can't use sock, _, _ as it keeks a reference to exceptions

            if sock is None:
                exceptions = [exc for sub in exceptions for exc in sub]
                try:
                    if all_errors:
                        raise ExceptionGroup("create_connection failed", exceptions)
                    if len(exceptions) == 1:
                        raise exceptions[0]
                    elif exceptions:
                        # If they all have the same str(), raise one.
                        model = str(exceptions[0])
                        if all(str(exc) == model for exc in exceptions):
                            raise exceptions[0]
                        # Raise a combined exception so the user can see all
                        # the various error messages.
                        raise OSError('Multiple exceptions: {}'.format(
                            ', '.join(str(exc) for exc in exceptions)))
                    else:
                        # No exceptions were collected, raise a timeout error
                        raise TimeoutError('create_connection failed')
                finally:
                    exceptions = None

        else:
            if sock is None:
                raise ValueError(
                    'host and port was not specified and no sock specified')
            if sock.type != socket.SOCK_STREAM:
                # We allow AF_INET, AF_INET6, AF_UNIX as long as they
                # are SOCK_STREAM.
                # We support passing AF_UNIX sockets even though we have
                # a dedicated API for that: create_unix_connection.
                # Disallowing AF_UNIX in this method, breaks backwards
                # compatibility.

View on GitHub (pinned to bc6749cc3b)