From e09cb3b5d61a3ca6ea786ec086e3a74b675bfd2e Mon Sep 17 00:00:00 2001 From: Kadir Can Ozden <101993364+bysiber@users.noreply.github.com> Date: Fri, 20 Feb 2026 05:13:08 +0300 Subject: [PATCH] fix: handle OSError in _create_stream without NameError If IOStream() constructor raises OSError, the except handler references 'stream' which was never assigned, causing a NameError that masks the original error. Also close the socket to prevent a resource leak. --- pr_body.md | 28 ++++++++++++++++++++++++++++ tornado/tcpclient.py | 3 ++- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 pr_body.md diff --git a/pr_body.md b/pr_body.md new file mode 100644 index 0000000000..45318c3fdf --- /dev/null +++ b/pr_body.md @@ -0,0 +1,28 @@ +Several `raise` statements across the codebase pass format arguments to exception constructors using a comma instead of `%` operator: + +```python +# Before (comma creates a tuple message): +raise ValueError("message %s", value) + +# After (proper string formatting): +raise ValueError("message %s" % value) +``` + +When Python's `Exception.__init__` receives multiple arguments, `str(e)` shows the raw tuple representation instead of a formatted message. For example, `ValueError("unsupported auth_mode %s", "digest")` displays as: + +``` +ValueError: ('unsupported auth_mode %s', 'digest') +``` + +instead of: + +``` +ValueError: unsupported auth_mode digest +``` + +Affected locations: +- `web.py`: `_convert_header_value`, `xsrf_token`, `stream_request_body`, `_has_stream_request_body` +- `websocket.py`: `_PerMessageDeflateCompressor.__init__`, `_PerMessageDeflateDecompressor.__init__`, `_process_server_headers` +- `simple_httpclient.py`: HTTP basic auth mode validation +- `netutil.py`: Unix socket bind validation +- `concurrent.py`: `run_on_executor` argument validation diff --git a/tornado/tcpclient.py b/tornado/tcpclient.py index 5b2a9f3fcd..26d9724863 100644 --- a/tornado/tcpclient.py +++ b/tornado/tcpclient.py @@ -326,6 +326,7 @@ def _create_stream( except OSError as e: fu = Future() # type: Future[IOStream] fu.set_exception(e) - return stream, fu + socket_obj.close() + return socket_obj, fu else: return stream, stream.connect(addr)