aio-libs/aiohttp · error · RuntimeError
Session and connector have to use same event loop
Error message
Session and connector have to use same event loop
What it means
Raised in ClientSession.__init__ (client.py:377) when the user-supplied `connector` was bound to a different asyncio event loop than the one currently running when the session is constructed. aiohttp pins the connector to its loop at creation; the session refuses to operate across loops to avoid cross-loop I/O corruption. The guard compares `connector._loop` to the loop returned by `asyncio.get_running_loop()` at session construction time.
Source
Thrown at aiohttp/client.py:377
DeprecationWarning,
stacklevel=2,
)
if connector is None:
connector = TCPConnector(ssl_shutdown_timeout=ssl_shutdown_timeout)
# Initialize these three attrs before raising any exception,
# they are used in __del__
self._connector = connector
self._loop = loop
if loop.get_debug():
self._source_traceback: traceback.StackSummary | None = (
traceback.extract_stack(sys._getframe(1))
)
else:
self._source_traceback = None
if connector._loop is not loop:
raise RuntimeError("Session and connector have to use same event loop")
if cookie_jar is None:
cookie_jar = CookieJar()
self._cookie_jar = cookie_jar
if cookies:
self._cookie_jar.update_cookies(cookies)
self._connector_owner = connector_owner
self._version = version
self._json_serialize = json_serialize
self._json_serialize_bytes = json_serialize_bytes
self._raise_for_status = raise_for_status
self._auto_decompress = auto_decompress
self._trust_env = trust_env
self._requote_redirect_url = requote_redirect_url
self._read_bufsize = read_bufsize
self._max_line_size = max_line_sizeView on GitHub (pinned to c0ef574e29)
Solutions
- Construct both the connector and the session inside the same `async` function / same event loop.
- Drop the explicit `connector=` argument and let the session create its own `TCPConnector()` (it does so at client.py:364 when `connector is None`).
- If you must share a connector, create it lazily inside the running loop and reuse it only within that loop's lifetime.
Example fix
// before
connector = aiohttp.TCPConnector() # built at import time, no loop
async def main():
session = aiohttp.ClientSession(connector=connector)
// after
async def main():
connector = aiohttp.TCPConnector()
session = aiohttp.ClientSession(connector=connector) Defensive patterns
Strategy: validation
Validate before calling
import asyncio
def same_loop(connector) -> bool:
try:
running = asyncio.get_running_loop()
except RuntimeError:
return False
return connector._loop is running Try / catch
try:
session = aiohttp.ClientSession(connector=connector)
except RuntimeError as e:
if 'same event loop' in str(e):
# rebuild connector in the current loop
connector = aiohttp.TCPConnector()
session = aiohttp.ClientSession(connector=connector)
else:
raise Prevention
- Construct the connector and session inside the same async function.
- Never create connectors at module import time.
- Prefer letting ClientSession create its own connector (omit the `connector=` arg).
- In tests, use aiohttp's pytest-aiohttp plugin which manages loop/session fixtures correctly.
When it happens
Trigger: Creating a `TCPConnector()` in one event loop/coroutine and then constructing `ClientSession(connector=that_connector)` inside a different loop (e.g., created the connector at import time outside any loop, or reused a connector across `asyncio.run()` calls).
Common situations: Module-level `connector = TCPConnector()` evaluated before any loop exists; reusing a connector after `asyncio.run()` tears down and starts a fresh loop; mixing threads with separate loops; test fixtures that build the connector in `setUp` but run the test in a new loop.
Related errors
- Connection timeout to host {url}
- base_url must have a trailing '/'
- ssl should be SSLContext, Fingerprint, or bool, got {ssl!r}
- timeout parameter cannot be of {type} type, please use 'time
- Cannot initialize a TLS-in-TLS connection to host {req.url.h
AI-assisted analysis of aio-libs/aiohttp@c0ef574e29 (2026-08-04).
Data as JSON: /data/errors/d052c15373419ffc.json.
Report an issue: GitHub.