https://github.com/python/cpython/commit/b2247bb07a5c509030fb66caf25bd33bee5523b5
commit: b2247bb07a5c509030fb66caf25bd33bee5523b5
branch: 3.15
author: Miss Islington (bot) <[email protected]>
committer: asvetlov <[email protected]>
date: 2026-11-04T10:01:10+01:00
summary:

[3.15] gh-161076: Ignore setsockopt(TCP_NODELAY) errors in asyncio (GH-161253) 
(#161301)

gh-161076: Ignore setsockopt(TCP_NODELAY) errors in asyncio (GH-161253)
(cherry picked from commit 405f12722cb7631f15d5b6df5825a2262209d9d8)

Co-authored-by: Andrew Svetlov <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-11-03-12-00-00.gh-issue-161076.nOdLy1.rst
M Lib/asyncio/base_events.py
M Lib/test/test_asyncio/test_base_events.py

diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py
index 59c61f9ba657a1..a2aa304f868343 100644
--- a/Lib/asyncio/base_events.py
+++ b/Lib/asyncio/base_events.py
@@ -195,7 +195,13 @@ def _set_nodelay(sock):
         if (sock.family in {socket.AF_INET, socket.AF_INET6} and
                 sock.type == socket.SOCK_STREAM and
                 sock.proto == socket.IPPROTO_TCP):
-            sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+            try:
+                sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+            except OSError:
+                # TCP_NODELAY is only a latency optimization.  It can fail
+                # on a connection already reset by the peer (e.g. EINVAL
+                # on macOS); the error will surface on the next I/O.
+                pass
 else:
     def _set_nodelay(sock):
         pass
diff --git a/Lib/test/test_asyncio/test_base_events.py 
b/Lib/test/test_asyncio/test_base_events.py
index 01529a9a2c1a60..68abcb026ad38e 100644
--- a/Lib/test/test_asyncio/test_base_events.py
+++ b/Lib/test/test_asyncio/test_base_events.py
@@ -2426,6 +2426,17 @@ def test_set_nodelay(self):
             sock.setblocking(False)
             self.check_set_nodelay(sock)
 
+    @unittest.skipUnless(hasattr(socket, 'TCP_NODELAY'),
+                         'need socket.TCP_NODELAY')
+    def test_set_nodelay_error(self):
+        # gh-161076: a failing setsockopt() must not break transport creation.
+        sock = mock.Mock(family=socket.AF_INET, type=socket.SOCK_STREAM,
+                         proto=socket.IPPROTO_TCP)
+        sock.setsockopt.side_effect = OSError(errno.EINVAL, 'Invalid argument')
+        base_events._set_nodelay(sock)
+        sock.setsockopt.assert_called_once_with(
+            socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+
 
 
 if __name__ == '__main__':
diff --git 
a/Misc/NEWS.d/next/Library/2026-11-03-12-00-00.gh-issue-161076.nOdLy1.rst 
b/Misc/NEWS.d/next/Library/2026-11-03-12-00-00.gh-issue-161076.nOdLy1.rst
new file mode 100644
index 00000000000000..bc286d0a676c02
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-11-03-12-00-00.gh-issue-161076.nOdLy1.rst
@@ -0,0 +1,5 @@
+Fix :mod:`asyncio` leaving a half-created transport registered with the
+event loop and the server when setting ``TCP_NODELAY`` on a socket fails.
+Such a failure could make :meth:`asyncio.Server.wait_closed` hang and
+prevent new connections from being served.  Errors from
+``setsockopt(TCP_NODELAY)`` are now ignored.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to