python/cpython · error · ExceptionGroup
create_connection failed
Error message
create_connection failed
What it means
The message of the ExceptionGroup raised by create_connection (Python 3.11+ with all_errors=True, or 3.12+ where all_errors defaults True) when every connection attempt failed. Each attempted address contributed one exception; asyncio groups them so the caller can inspect all root causes (DNS, refused, timeouts) rather than just the first. The group itself is an ExceptionGroup, not an OSError.
Source
Thrown at Lib/asyncio/base_events.py:1172
else: # using happy eyeballs
sock = (await staggered.staggered_race(
(
# can't use functools.partial as it keeps a reference
# to exceptions
lambda addrinfo=addrinfo: self._connect_sock(
exceptions, addrinfo, laddr_infos
)
for addrinfo in infos
),
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:View on GitHub (pinned to bc6749cc3b)
Solutions
- Catch ExceptionGroup (or use except* syntax) and inspect .exceptions for root causes.
- Pass all_errors=False to get legacy behavior (single exception or combined OSError), if compatibility matters.
- Retry at a higher level with backoff once you have logged the per-address causes.
Example fix
// before
try:
await loop.create_connection(proto, host, port)
except OSError as e: # misses ExceptionGroup on 3.12+
log(e)
// after
try:
await loop.create_connection(proto, host, port)
except* OSError as eg:
for exc in eg.exceptions:
log(f'attempt failed: {exc!r}') Defensive patterns
Strategy: try-catch
Try / catch
try:
tp, pr = await loop.create_connection(proto, host, port)
except* OSError as eg:
for exc in eg.exceptions:
log.warning(f'connect attempt failed: {exc!r}')
raise
except ExceptionGroup as eg:
for exc in eg.exceptions:
log.warning(f'connect attempt failed: {exc!r}')
raise Prevention
- On Python 3.12+, expect ExceptionGroup from create_connection and catch with except* or bare ExceptionGroup.
- Set all_errors=False explicitly if your error handling assumes OSError.
- Log eg.exceptions individually to diagnose per-address failures.
When it happens
Trigger: loop.create_connection(..., all_errors=True) to a multi-address host (dual-stack A+AAAA) where both the IPv6 and IPv4 attempts fail — e.g. firewall drops v6 (timeout) and v4 gets ECONNREFUSED. Catching OSError alone will NOT catch this ExceptionGroup.
Common situations: Upgrading to Python 3.12 where all_errors defaulted to True changed exception types; servers reachable on only one family; flaky networks where different attempts fail differently.
Related errors
- Multiple exceptions: {}
- staggered race failed
- no matching local address with {family=} found
- server_hostname is only meaningful with ssl
- host/port and sock can not be specified at the same time
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/bf704f16ac82a6c0.
Report an issue: GitHub.