aio-libs/aiohttp · error · ClientConnectionError
Connector is closed
Error message
Connector is closed
What it means
Raised in _resolve_host when use_dns_cache is False and self._closed is True at the moment a DNS resolve is attempted. It is the DNS-path counterpart of error 88: the connector was closed (or is closing) while a request still needs it, so rather than dispatch a resolve against a dead connector aiohttp raises ClientConnectionError immediately.
Solutions
- Check `if connector.closed` before each request and rebuild when closed.
- Keep one long-lived connector/session instead of opening and closing per cycle.
- Await all in-flight requests before closing the connector.
- When use_dns_cache=False, prefer creating a fresh connector per logical session.
Example fix
# before
connector = aiohttp.TCPConnector(use_dns_cache=False)
# ... later, after connector.close()
await session.get(url)
# after
if connector.closed:
connector = aiohttp.TCPConnector(use_dns_cache=False)
session = aiohttp.ClientSession(connector=connector)
await session.get(url) Defensive patterns
Strategy: try-catch
Validate before calling
async def resolve_or_rebuild(connector, session, host, port):
if connector.closed:
raise aiohttp.ClientConnectionError('Connector is closed; rebuild before retry')
return await connector._resolve_host(host, port) # or issue the request instead Type guard
null
Try / catch
try:
resp = await session.get(url)
except aiohttp.ClientConnectionError as exc:
if 'Connector is closed' in str(exc):
connector = aiohttp.TCPConnector(use_dns_cache=False)
session = aiohttp.ClientSession(connector=connector)
resp = await session.get(url)
else:
raise Prevention
- Check `connector.closed` before each request when reuse patterns are unpredictable.
- Prefer one long-lived connector rather than recycling with use_dns_cache=False.
- Await all in-flight requests before closing the connector or session.
When it happens
Trigger: Disabling DNS caching and then issuing a request after connector.close(); a session closed by an `async with` exit that still has a pending request; reconnect logic reusing a closed connector.
Common situations: use_dns_cache=False for low-latency clients combined with aggressive connector recycling; test teardown closing the connector before slow requests finish; microservices that pool connectors but close them on config reload.
Related errors
- Connector is closed.
- either both host and port or none of them are allowed
- Already started
- Call .prepare() first
- Call runner.setup() before making a site
AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11).
Data as JSON: /api/errors/95d2e283c018ceee.
Report an issue: GitHub.
Appendix: source
Thrown at aiohttp/connector.py:1149
raise InvalidUrlClientError(host, "is not a canonical IPv4 address")
return [
{
"hostname": host,
"host": host,
"port": port,
"family": self._family,
"proto": 0,
"flags": 0,
}
]
if not self._use_dns_cache:
if traces:
for trace in traces:
await trace.send_dns_resolvehost_start(host)
if self._closed:
raise ClientConnectionError("Connector is closed")
res = await self._resolver.resolve(host, port, family=self._family)
if traces:
for trace in traces:
await trace.send_dns_resolvehost_end(host)
return res
key = (host, port)
if key in self._cached_hosts and not self._cached_hosts.expired(key):
# get result early, before any await (#4014)
result = self._cached_hosts.next_addrs(key)
if traces:
for trace in traces:
await trace.send_dns_cache_hit(host)
return resultView on GitHub (pinned to d041d4d0fd)