Jump to solution
Verify

The Fix

Fixes the issue where the TCPConnector does not use the session's event loop, which raises exceptions when an explicit loop is passed to ClientSession.

Based on closed aio-libs/aiohttp issue #11147 · PR/commit linked

Production note: Most teams hit this during upgrades or environment changes. Roll out with a canary and smoke critical endpoints (health, OpenAPI/docs) before 100%.

Jump to Verify Open PR/Commit
@@ -0,0 +1 @@ @@ -0,0 +1 @@ +Added ``ssl_shutdown_timeout`` parameter to :py:class:`~aiohttp.ClientSession` and :py:class:`~aiohttp.TCPConnector` to control the grace period for SSL shutdown handshake on TLS connections. This helps prevent "connection reset" errors on the server side while avoiding excessive delays during connector cleanup. Note: This parameter only takes effect on Python 3.11+ -- by :user:`bdraco`. diff --git a/CHANGES/11094.feature.rst b/CHANGES/11094.feature.rst new file mode 120000
repro.py
from asyncio import new_event_loop from aiohttp import ClientSession async def test(): other_loop = new_event_loop() _ = ClientSession(loop=other_loop) loop = new_event_loop() loop.run_until_complete(test()) loop.close()
verify
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
fix.md
Option A — Apply the official fix\nFixes the issue where the TCPConnector does not use the session's event loop, which raises exceptions when an explicit loop is passed to ClientSession.\nWhen NOT to use: This fix is not applicable if the application relies on the previous behavior of ClientSession.\n\n

Why This Fix Works in Production

  • Trigger: loop.run_until_complete(test())
  • Mechanism: The loop parameter of ClientSession is not passed to the TCPConnector, causing runtime exceptions
Production impact:
  • If left unfixed, the same config can fail only in production (env differences), causing startup failures or partial feature outages.

Why This Breaks in Prod

  • The loop parameter of ClientSession is not passed to the TCPConnector, causing runtime exceptions
  • Surfaces as: Traceback (most recent call last):

Proof / Evidence

Discussion

High-signal excerpts from the issue thread (symptoms, repros, edge-cases).

“The loop=loop argument was removed in https://github.com/aio-libs/aiohttp/pull/11095.”
@meyerj · 2025-06-12 · source
“We removed it on master a long time ago. Looks like it didn't get preserved in the backport so we need to do a pr…”
@bdraco · 2025-06-12 · source

Failure Signature (Search String)

  • loop.run_until_complete(test())

Error Message

Stack trace
error.txt
Error Message ------------- Traceback (most recent call last): File "C:\Users\***\Documents\PyCharm\Test\test.py", line 12, in <module> loop.run_until_complete(test()) File "C:\Program Files\Python312\Lib\asyncio\base_events.py", line 691, in run_until_complete return future.result() ^^^^^^^^^^^^^^^ File "C:\Users\***\Documents\PyCharm\Test\test.py", line 8, in test _ = ClientSession(loop=other_loop) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\***\.virtualenvs\Test-hO5JO9V5\Lib\site-packages\aiohttp\client.py", line 368, in __init__ raise RuntimeError("Session and connector has to use same event loop") RuntimeError: Session and connector has to use same event loop
Stack trace
error.txt
Error Message ------------- Traceback (most recent call last): File "C:\Users\***\Documents\PyCharm\Test\test.py", line 7, in <module> session = ClientSession(loop=loop) ^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\***\.virtualenvs\Test-hO5JO9V5\Lib\site-packages\aiohttp\client.py", line 365, in __init__ connector = TCPConnector(ssl_shutdown_timeout=ssl_shutdown_timeout) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\***\.virtualenvs\Test-hO5JO9V5\Lib\site-packages\aiohttp\connector.py", line 918, in __init__ super().__init__( File "C:\Users\***\.virtualenvs\Test-hO5JO9V5\Lib\site-packages\aiohttp\connector.py", line 288, in __init__ loop = loop or asyncio.get_running_loop() ^^^^^^^^^^^^^^^^^^^^^^^^^^ RuntimeError: no running event loop

Minimal Reproduction

repro.py
from asyncio import new_event_loop from aiohttp import ClientSession async def test(): other_loop = new_event_loop() _ = ClientSession(loop=other_loop) loop = new_event_loop() loop.run_until_complete(test()) loop.close()

What Broke

Creating ClientSession with a different loop leads to RuntimeError exceptions in production.

Why It Broke

The loop parameter of ClientSession is not passed to the TCPConnector, causing runtime exceptions

Fix Options (Details)

Option A — Apply the official fix

Fixes the issue where the TCPConnector does not use the session's event loop, which raises exceptions when an explicit loop is passed to ClientSession.

When NOT to use: This fix is not applicable if the application relies on the previous behavior of ClientSession.

Fix reference: https://github.com/aio-libs/aiohttp/pull/11095

Last verified: 2026-02-09. Validate in your environment.

Get updates

We publish verified fixes weekly. No spam.

Subscribe

When NOT to Use This Fix

  • This fix is not applicable if the application relies on the previous behavior of ClientSession.

Verify Fix

verify
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.

Did This Fix Work in Your Case?

Quick signal helps us prioritize which fixes to verify and improve.

Prevention

  • Add a TLS smoke test that performs a real handshake in CI (include CA bundle validation and hostname checks).
  • Alert on handshake failures by error string and endpoint to catch cert/CA changes quickly.
  • Make timeouts explicit and test them (unit + integration) to avoid silent behavior changes.
  • Instrument retries (attempt count + reason) and alert on spikes to catch dependency slowdowns.

Related Issues

No related fixes found.

Sources

We don’t republish the full GitHub discussion text. Use the links above for context.