From 497df2e83921023e3b88f2adb99390f2ac0b55e5 Mon Sep 17 00:00:00 2001 From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com> Date: Sat, 31 May 2025 00:13:17 -0500 Subject: [PATCH 1/3] [PR #11100/947247fd backport][3.12] Fix spurious "Future exception was never retrieved" warnings for connection lost errors (#11101) Co-authored-by: J. Nick Koston --- CHANGES/11100.bugfix.rst | 3 +++ aiohttp/client_proto.py | 6 ++++++ tests/test_client_proto.py | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 CHANGES/11100.bugfix.rst diff --git a/CHANGES/11100.bugfix.rst b/CHANGES/11100.bugfix.rst new file mode 100644 index 00000000000..a7c54059a14 --- /dev/null +++ b/CHANGES/11100.bugfix.rst @@ -0,0 +1,3 @@ +Fixed spurious "Future exception was never retrieved" warnings for connection lost errors when the connector is not closed -- by :user:`bdraco`. + +When connections are lost, the exception is now marked as retrieved since it is always propagated through other means, preventing unnecessary warnings in logs. diff --git a/aiohttp/client_proto.py b/aiohttp/client_proto.py index 6a0318e553a..2d8c2e578c4 100644 --- a/aiohttp/client_proto.py +++ b/aiohttp/client_proto.py @@ -97,6 +97,12 @@ def connection_lost(self, exc: Optional[BaseException]) -> None: ), original_connection_error, ) + # Mark the exception as retrieved to prevent + # "Future exception was never retrieved" warnings + # The exception is always passed on through + # other means, so this is safe + with suppress(Exception): + self.closed.exception() if self._payload_parser is not None: with suppress(Exception): # FIXME: log this somehow? diff --git a/tests/test_client_proto.py b/tests/test_client_proto.py index af1286dc310..c7fb79a5f44 100644 --- a/tests/test_client_proto.py +++ b/tests/test_client_proto.py @@ -247,3 +247,22 @@ async def test_connection_lost_sets_transport_to_none(loop, mocker) -> None: proto.connection_lost(OSError()) assert proto.transport is None + + +async def test_connection_lost_exception_is_marked_retrieved( + loop: asyncio.AbstractEventLoop, +) -> None: + """Test that connection_lost properly handles exceptions without warnings.""" + proto = ResponseHandler(loop=loop) + proto.connection_made(mock.Mock()) + + # Simulate an SSL shutdown timeout error + ssl_error = TimeoutError("SSL shutdown timed out") + proto.connection_lost(ssl_error) + + # Verify the exception was set on the closed future + assert proto.closed.done() + exc = proto.closed.exception() + assert exc is not None + assert "Connection lost: SSL shutdown timed out" in str(exc) + assert exc.__cause__ is ssl_error From 623690d815f7127f0beb170ce7d36b384cf4f55c Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 31 May 2025 00:16:20 -0500 Subject: [PATCH 2/3] Release 3.12.6 (#11103) --- CHANGES.rst | 20 ++++++++++++++++++++ CHANGES/11100.bugfix.rst | 3 --- aiohttp/__init__.py | 2 +- 3 files changed, 21 insertions(+), 4 deletions(-) delete mode 100644 CHANGES/11100.bugfix.rst diff --git a/CHANGES.rst b/CHANGES.rst index 360750dd88f..0e10454a3d1 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -10,6 +10,26 @@ .. towncrier release notes start +3.12.6 (2025-05-31) +=================== + +Bug fixes +--------- + +- Fixed spurious "Future exception was never retrieved" warnings for connection lost errors when the connector is not closed -- by :user:`bdraco`. + + When connections are lost, the exception is now marked as retrieved since it is always propagated through other means, preventing unnecessary warnings in logs. + + + *Related issues and pull requests on GitHub:* + :issue:`11100`. + + + + +---- + + 3.12.5 (2025-05-30) =================== diff --git a/CHANGES/11100.bugfix.rst b/CHANGES/11100.bugfix.rst deleted file mode 100644 index a7c54059a14..00000000000 --- a/CHANGES/11100.bugfix.rst +++ /dev/null @@ -1,3 +0,0 @@ -Fixed spurious "Future exception was never retrieved" warnings for connection lost errors when the connector is not closed -- by :user:`bdraco`. - -When connections are lost, the exception is now marked as retrieved since it is always propagated through other means, preventing unnecessary warnings in logs. diff --git a/aiohttp/__init__.py b/aiohttp/__init__.py index fc946e05e9f..6a0b167be83 100644 --- a/aiohttp/__init__.py +++ b/aiohttp/__init__.py @@ -1,4 +1,4 @@ -__version__ = "3.12.5" +__version__ = "3.12.6" from typing import TYPE_CHECKING, Tuple From 379321dce16fcff98ed1df3c6a72ab9bba7f02da Mon Sep 17 00:00:00 2001 From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com> Date: Sat, 31 May 2025 05:34:01 +0000 Subject: [PATCH 3/3] [PR #11100/947247fd backport][3.13] Fix spurious "Future exception was never retrieved" warnings for connection lost errors (#11102) Co-authored-by: J. Nick Koston --- CHANGES/11100.bugfix.rst | 3 +++ aiohttp/client_proto.py | 6 ++++++ tests/test_client_proto.py | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 CHANGES/11100.bugfix.rst diff --git a/CHANGES/11100.bugfix.rst b/CHANGES/11100.bugfix.rst new file mode 100644 index 00000000000..a7c54059a14 --- /dev/null +++ b/CHANGES/11100.bugfix.rst @@ -0,0 +1,3 @@ +Fixed spurious "Future exception was never retrieved" warnings for connection lost errors when the connector is not closed -- by :user:`bdraco`. + +When connections are lost, the exception is now marked as retrieved since it is always propagated through other means, preventing unnecessary warnings in logs. diff --git a/aiohttp/client_proto.py b/aiohttp/client_proto.py index 6a0318e553a..2d8c2e578c4 100644 --- a/aiohttp/client_proto.py +++ b/aiohttp/client_proto.py @@ -97,6 +97,12 @@ def connection_lost(self, exc: Optional[BaseException]) -> None: ), original_connection_error, ) + # Mark the exception as retrieved to prevent + # "Future exception was never retrieved" warnings + # The exception is always passed on through + # other means, so this is safe + with suppress(Exception): + self.closed.exception() if self._payload_parser is not None: with suppress(Exception): # FIXME: log this somehow? diff --git a/tests/test_client_proto.py b/tests/test_client_proto.py index af1286dc310..c7fb79a5f44 100644 --- a/tests/test_client_proto.py +++ b/tests/test_client_proto.py @@ -247,3 +247,22 @@ async def test_connection_lost_sets_transport_to_none(loop, mocker) -> None: proto.connection_lost(OSError()) assert proto.transport is None + + +async def test_connection_lost_exception_is_marked_retrieved( + loop: asyncio.AbstractEventLoop, +) -> None: + """Test that connection_lost properly handles exceptions without warnings.""" + proto = ResponseHandler(loop=loop) + proto.connection_made(mock.Mock()) + + # Simulate an SSL shutdown timeout error + ssl_error = TimeoutError("SSL shutdown timed out") + proto.connection_lost(ssl_error) + + # Verify the exception was set on the closed future + assert proto.closed.done() + exc = proto.closed.exception() + assert exc is not None + assert "Connection lost: SSL shutdown timed out" in str(exc) + assert exc.__cause__ is ssl_error