Skip to content

gh-161076: Ignore setsockopt(TCP_NODELAY) errors in asyncio - #161253

Merged
kumaraditya303 merged 2 commits into
python:mainfrom
asvetlov:claude/cpython-issue-161076-c334f7
Nov 4, 2026
Merged

kumaraditya303 merged 2 commits into
python:mainfrom
asvetlov:claude/cpython-issue-161076-c334f7

Conversation

@asvetlov

@asvetlov asvetlov commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

setsockopt(TCP_NODELAY) can fail on an accepted socket, especially on macOS (EINVAL for a connection already reset by the peer). The failure happens after the transport has registered itself with the loop and the server, leaving a zombie transport behind.

TCP_NODELAY is only a latency optimization and doesn't change the transport's behavior, so _set_nodelay() now ignores OSError.

🤖 Generated with Claude Code

A failing setsockopt() in the transport constructor left the transport
registered with the loop and the server: later connections reusing the
fd failed and Server.wait_closed() hung. On the proactor loop the error
also closed the listening socket. TCP_NODELAY is only a latency
optimization, so ignore OSError from it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@asvetlov
asvetlov marked this pull request as ready for review November 3, 2026 16:38

@OsmnvAslan OsmnvAslan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick fix! I checked it against main with a reproducer that makes the real setsockopt(TCP_NODELAY) fail once for an accepted socket (rather than patching _set_nodelay()). On main the server is left with a zombie transport: later connections on the same fd fail and wait_closed() hangs. With this PR all three connections are served and wait_closed() returns. LGTM.

@kumaraditya303
kumaraditya303 merged commit 405f127 into python:main Nov 4, 2026
59 checks passed
@asvetlov asvetlov added needs backport to 3.14 bugs and security fixes needs backport to 3.15 bugs and security fixes labels Nov 4, 2026
@miss-islington-app

Copy link
Copy Markdown

Thanks @asvetlov for the PR, and @kumaraditya303 for merging it 🌮🎉.. I'm working now to backport this PR to: 3.15.
🐍🍒⛏🤖

@miss-islington-app

Copy link
Copy Markdown

Thanks @asvetlov for the PR, and @kumaraditya303 for merging it 🌮🎉.. I'm working now to backport this PR to: 3.14.
🐍🍒⛏🤖

@bedevere-app

bedevere-app Bot commented Nov 4, 2026

Copy link
Copy Markdown

GH-161301 is a backport of this pull request to the 3.15 branch.

@bedevere-app bedevere-app Bot removed the needs backport to 3.15 bugs and security fixes label Nov 4, 2026
@bedevere-app

bedevere-app Bot commented Nov 4, 2026

Copy link
Copy Markdown

GH-161302 is a backport of this pull request to the 3.14 branch.

@bedevere-app bedevere-app Bot removed the needs backport to 3.14 bugs and security fixes label Nov 4, 2026
@asvetlov

asvetlov commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

Thanks, @kumaraditya303

asvetlov added a commit that referenced this pull request Nov 4, 2026
…H-161253) (#161302)

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

Co-authored-by: Andrew Svetlov <andrew.svetlov@gmail.com>
asvetlov added a commit that referenced this pull request Nov 4, 2026
…H-161253) (#161301)

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

Co-authored-by: Andrew Svetlov <andrew.svetlov@gmail.com>
@bedevere-bot

Copy link
Copy Markdown

⚠️⚠️⚠️ Buildbot failure ⚠️⚠️⚠️

Hi! The buildbot AMD64 CentOS9 NoGIL Refleaks 3.15 (tier-1) has failed when building commit b2247bb.

What do you need to do:

  1. Don't panic.
  2. Check the buildbot page in the devguide if you don't know what the buildbots are or how they work.
  3. Go to the page of the buildbot that failed (https://buildbot.python.org/#/builders/2078/builds/604) and take a look at the build logs.
  4. Check if the failure is related to this commit (b2247bb) or if it is a false positive.
  5. If the failure is related to this commit, please, reflect that on the issue and make a new Pull Request with a fix.

You can take a look at the buildbot page here:

https://buildbot.python.org/#/builders/2078/builds/604

Failed tests:

  • test.test_concurrent_futures.test_interpreter_pool

Summary of the results of the build (if available):

==

Click to see traceback logs
TracebackType': 'TracebackType', 'FrameType': 'FrameType', 'FrameLocalsProxyType': 'FrameLocalsProxyType', 'GetSetDescriptorType': 'GetSetDescriptorType', 'MemberDescriptorType': 'MemberDescriptorType', 'UnionType': 'UnionType', 'NoneType': 'NoneType', 'NotImplementedType': 'NotImplementedType', 'CapsuleType': 'CapsuleType', 'LazyImportType': 'LazyImportType', 'Helper to provide extensibility for pickle.\n\nThis is only useful to add pickle support for extension types defined in\nC, not for instances of user-defined classes.\n': 'Helper to provide extensibility for pickle.\n\nThis is only useful to add pickle support for extension types defined in\nC, not for instances of user-defined classes.\n', 'reduction functions must be callable': 'reduction functions must be callable', 'constructor': 'constructor', 'ob_type': 'ob_type', 'pickle_function': 'pickle_function', 'constructor_ob': 'constructor_ob', '/home/buildbot/buildarea/3.15.itamaro-centos-aws.refleak.nogil/build/Lib/copyreg.py': '/home/buildbot/buildarea/3.15.itamaro-centos-aws.refleak.nogil/build/Lib/copyreg.py', 'pickle': 'pickle', 'constructors must be callable': 'constructors must be callable', 'pickle_complex': 'pickle_complex', 'operator': 'operator', 'getitem': 'getitem', 'Union': 'Union', 'pickle_union': 'pickle_union', 'pickle_super': 'pickle_super', '_reconstructor': '_reconstructor', 'cannot pickle ': 'cannot pickle ', 'a class that defines __slots__ without defining __getstate__ cannot be pickled': 'a class that defines __slots__ without defining __getstate__ cannot be pickled', ' object: a class that defines __slots__ without defining __getstate__ cannot be pickled with protocol ': ' object: a class that defines __slots__ without defining __getstate__ cannot be pickled with protocol ', '_HEAPTYPE': '_HEAPTYPE', '_new_type': '_new_type', '_reduce_ex': '_reduce_ex', 'Used by pickle protocol 4, instead of __newobj__ to allow classes with\nkeyword-only arguments to be pickled correctly.\n': 'Used by pickle protocol 4, instead of __newobj__ to allow classes with\nkeyword-only arguments to be pickled correctly.\n', "Return a list of slot names for a given class.\n\nThis needs to find slots defined by the class and its bases, so we\ncan't simply return the __slots__ attribute.  We must walk down\nthe Method Resolution Order and concatenate the __slots__ of each\nclass found there.  (This assumes classes don't modify their\n__slots__ attribute to misrepresent their slots after the class i


TracebackException.format_exception_only': 'TracebackException.format_exception_only', 'invalid syntax': 'invalid syntax', 'Perhaps you forgot a comma': 'Perhaps you forgot a comma', 'symbol': 'symbol', "invalid syntax. Did you mean '": "invalid syntax. Did you mean '", '_suggestions': '_suggestions', 'codeop': 'codeop', 'compile_command': 'compile_command', 'PyCF_ONLY_AST': 'PyCF_ONLY_AST', 'generate_tokens': 'generate_tokens', 'difflib': 'difflib', 'NAME': 'NAME', '_generate_suggestions': '_generate_suggestions', 'get_close_matches': 'get_close_matches', 'end_line': 'end_line', 'from_filename': 'from_filename', 'error_code': 'error_code', 'error_lines': 'error_lines', 'tokens': 'tokens', 'tokens_left_to_process': 'tokens_left_to_process', 'token': 'token', 'the_end': 'the_end', 'max_matches': 'max_matches', 'matches': 'matches', 'the_lines': 'the_lines', 'the_line': 'the_line', '_find_keyword_typos': '_find_keyword_typos', 'TracebackException._find_keyword_typos': 'TracebackException._find_keyword_typos', 'Format SyntaxError exceptions (internal helper).': 'Format SyntaxError exceptions (internal helper).', '  File {}"{}"{}, line {}{}{}\n': '  File {}"{}"{}, line {}{}{}\n', ' ({})': ' ({})', ' \n\x0c': ' \n\x0c', '    {}\n': '    {}\n', '    {}{}{}{}\n': '    {}{}{}{}\n', '<no detail available>': '<no detail available>', '{}{}{}: {}{}{}{}\n': '{}{}{}: {}{}{}{}\n', 'filename_suffix': 'filename_suffix', 'rtext': 'rtext', 'ltext': 'ltext', 'spaces': 'spaces', 'dp_colno': 'dp_colno', 'highlighted': 'highlighted', 'caret_count': 'caret_count', 'start_color': 'start_color', 'end_color': 'end_color', 'TracebackException._format_syntax_error': 'TracebackException._format_syntax_error', '_ctx': '_ctx', 'Format the exception.\n\nIf chain is not *True*, *__cause__* and *__context__* will not be formatted.\n\nThe return value is a generator of strings, each ending in a newline and\nsome containing internal newlines. `print_exception` is a wrapper around\nthis method which just prints the lines to a file.\n\nThe message indicating which exception occurred is always the last\nstring in the output.\n': 'Format the exception.\n\nIf chain is not *True*, *__cause__* and *__context__* will not be formatted.\n\nThe return value is a generator of strings, each ending in a newline and\nsome containing internal newlines. `print_exception` is a wrapper around\nthis method which just prints the lines to a file.\n\nThe message indicating which exception occurred is always the last\nstring in the output.\n', 'Traceback (most recent call last):\n': 'Traceback (most recent call last):\n', '... (max_group_depth is ': '... (max_group_depth is ', ')\n': ')\n', 'Exception Group Traceback (most recent call last):\n': 'Exception Group Traceback (most recent call last):\n', '+-': '+-', '+---------------- ': '+---------------- ', ' ----------------\n': ' ----------------\n', 'and ': 'and ', ' more exception': ' more exception', '+------------------------------------\n': '+------------------------------------\n', '_cause_message': '_cause_message', '_context_message': '_context_message', 'chained_msg': 'chained_msg', 'chained_exc': 'chained_exc', 'is_toplevel': 'is_toplevel', 'num_excs': 'num_excs', 'truncated': 'truncated', 'remaining': 'remaining', 'plural': 'plural', 'TracebackException.format': 'TracebackException.format', "Print the result of self.format(chain=chain) to 'file'.": "Print the result of self.format(chain=chain) to 'file'.", 'TracebackException.print': 'TracebackException.print', 'push': 'push', 'addAll': 'addAll', "Use 'x in list'.": "Use 'x in list'.", "Did you mean to use a 'set' object?": "Did you mean to use a 'set' object?", 'toUpperCase': 'toUpperCase', 'toLowerCase': 'toLowerCase', 'trimStart': 'trimStart', 'trimEnd': 'trimEnd', 'keySet': 'keySet', 'entrySet': 'entrySet', 'putAll': 'putAll', 'Use d[k] = v.': 'Use d[k] = v.', "Did you mean to use a 'list' object?": "Did you mean 


Traceback (most recent\ncall last):"; (2


TracebackException instances from exception\nobjects, or the constructor to create TracebackException instances from\nindividual components.\n\n- :attr:`__cause__` A TracebackException of the original *__cause__*.\n- :attr:`__context__` A TracebackException of the original *__context__*.\n- :attr:`exceptions` For exception groups - a list of TracebackException\n  instances for the nested *exceptions*.  ``None`` for other exceptions.\n- :attr:`__suppress_context__` The *__suppress_context__* value from the\n  original exception.\n- :attr:`stack` A `StackSummary` representing the traceback.\n- :attr:`exc_type` (deprecated) The class of the original traceback.\n- :attr:`exc_type_str` String display of exc_type\n- :attr:`filename` For syntax errors - the filename where the error\n  occurred.\n- :attr:`lineno` For syntax errors - the linenumber where the error\n  occurred.\n- :attr:`end_lineno` For syntax errors - the end linenumber where the error\n  occurred. Can be `None` if not present.\n- :attr:`text` For syntax errors - the text where the error\n  occurred.\n- :attr:`offset` For syntax errors - the offset into the text where the\n  error occurred.\n- :attr:`end_offset` For syntax errors - the end offset into the text where\n  the error occurred. Can be `None` if not present.\n- :attr:`msg` For syntax errors - the compiler error message.\n": "An exception ready for rendering.\n\nThe traceback module captures enough attributes from the original exception\nto this intermediary form to ensure that no references are held, while\nstill being able to fully print or format it.\n\nmax_group_width and max_group_depth control the formatting of exception\ngroups. The depth refers to the nesting level of the group, and the width\nrefers to the size of a single exception group's exceptions array. The\nformatted output is truncated when either limit is exceeded.\n\nUse `from_exception` to create TracebackException instances from exception\nobjects, or the constructor to create TracebackException instances from\nindividual components.\n\n- :attr:`__cause__` A TracebackException of the original *__cause__*.\n- :attr:`__context__` A TracebackException of the original *__context__*.\n- :attr:`exceptions` For exception groups - a list of TracebackException\n  instances for the nested *exceptions*.  ``None`` for other exceptions.\n- :attr:`__suppress_context__` The *__suppress_context__* value from the\n  original exception.\n- :attr:`stack` A `StackSummary` representing the traceback.\n- :attr:`exc_type` (deprecated) The class of the original traceback.\n- :attr:`exc_type_str` String display of exc_type\n- :attr:`filename` For syntax errors - the filename where the error\n  occurred.\n- :attr:`lineno` For syntax errors - the linenumber where the error\n  occurred.\n- :attr:`end_lineno` For syntax errors - the end linenumber where the error\n  occurred. Can be `None` if not present.\n- :attr:`text` For syntax errors - the text where the error\n  occurred.\n- :attr:`off

@asvetlov

asvetlov commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

The failure is not related to the PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants