qa: Account for unset errno in ConnectionResetError #33875

pull hodlinator wants to merge 1 commits into bitcoin:master from hodlinator:2025/11/RemoteDisconnect_err changing 1 files +9 βˆ’4
  1. hodlinator commented at 9:10 pm on November 14, 2025: contributor

    The lack of errno can cause unclear and long log output.

    Issue can be triggered by:

    0--- a/src/httpserver.cpp
    1+++ b/src/httpserver.cpp
    2@@ -263,6 +263,7 @@ std::string RequestMethodString(HTTPRequest::RequestMethod m)
    3 /** HTTP request callback */
    4 static void http_request_cb(struct evhttp_request* req, void* arg)
    5 {
    6+    throw std::runtime_error{"Hello"};
    7     evhttp_connection* conn{evhttp_request_get_connection(req)};
    8     // Track active requests
    9     {
    

    and running a functional test such as test/functional/feature_abortnode.py.

    http.client.RemoteDisconnected not specifying errno to ConnectionResetError-ctor: https://github.com/python/cpython/blob/ce4b0ede16aea62ee7b1e02df7e1538102a356da/Lib/http/client.py#L1556C9-L1556C29

    Log before

     02025-11-14T20:53:05.272804Z TestFramework (ERROR): Unexpected exception
     1Traceback (most recent call last):
     2  File "/home/hodlinator/bc/3/test/functional/test_framework/test_framework.py", line 138, in main
     3    self.setup()
     4    ~~~~~~~~~~^^
     5  File "/home/hodlinator/bc/3/test/functional/test_framework/test_framework.py", line 268, in setup
     6    self.setup_network()
     7    ~~~~~~~~~~~~~~~~~~^^
     8  File "/home/hodlinator/bc/3/./build/test/functional/feature_abortnode.py", line 21, in setup_network
     9    self.setup_nodes()
    10    ~~~~~~~~~~~~~~~~^^
    11  File "/home/hodlinator/bc/3/test/functional/test_framework/test_framework.py", line 381, in setup_nodes
    12    self.start_nodes()
    13    ~~~~~~~~~~~~~~~~^^
    14  File "/home/hodlinator/bc/3/test/functional/test_framework/test_framework.py", line 527, in start_nodes
    15    node.wait_for_rpc_connection()
    16    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
    17  File "/home/hodlinator/bc/3/test/functional/test_framework/test_node.py", line 326, in wait_for_rpc_connection
    18    rpc.getblockcount()
    19    ~~~~~~~~~~~~~~~~~^^
    20  File "/home/hodlinator/bc/3/test/functional/test_framework/coverage.py", line 50, in __call__
    21    return_val = self.auth_service_proxy_instance.__call__(*args, **kwargs)
    22  File "/home/hodlinator/bc/3/test/functional/test_framework/authproxy.py", line 137, in __call__
    23    response, status = self._request('POST', self.__url.path, postdata.encode('utf-8'))
    24                       ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    25  File "/home/hodlinator/bc/3/test/functional/test_framework/authproxy.py", line 111, in _request
    26    return self._get_response()
    27           ~~~~~~~~~~~~~~~~~~^^
    28  File "/home/hodlinator/bc/3/test/functional/test_framework/authproxy.py", line 174, in _get_response
    29    http_response = self.__conn.getresponse()
    30  File "/nix/store/62fdlzq1x1ak2lsxp4ij7ip5k9nia3hc-python3-3.13.7/lib/python3.13/http/client.py", line 1430, in getresponse
    31    response.begin()
    32    ~~~~~~~~~~~~~~^^
    33  File "/nix/store/62fdlzq1x1ak2lsxp4ij7ip5k9nia3hc-python3-3.13.7/lib/python3.13/http/client.py", line 331, in begin
    34    version, status, reason = self._read_status()
    35                              ~~~~~~~~~~~~~~~~~^^
    36  File "/nix/store/62fdlzq1x1ak2lsxp4ij7ip5k9nia3hc-python3-3.13.7/lib/python3.13/http/client.py", line 300, in _read_status
    37    raise RemoteDisconnected("Remote end closed connection without"
    38                             " response")
    39http.client.RemoteDisconnected: Remote end closed connection without response
    

    Log after

     02025-11-14T20:48:10.552126Z TestFramework (ERROR): Unexpected exception
     1Traceback (most recent call last):
     2  File "/home/hodlinator/bc/3/test/functional/test_framework/test_framework.py", line 138, in main
     3    self.setup()
     4    ~~~~~~~~~~^^
     5  File "/home/hodlinator/bc/3/test/functional/test_framework/test_framework.py", line 268, in setup
     6    self.setup_network()
     7    ~~~~~~~~~~~~~~~~~~^^
     8  File "/home/hodlinator/bc/3/./build/test/functional/feature_abortnode.py", line 21, in setup_network
     9    self.setup_nodes()
    10    ~~~~~~~~~~~~~~~~^^
    11  File "/home/hodlinator/bc/3/test/functional/test_framework/test_framework.py", line 381, in setup_nodes
    12    self.start_nodes()
    13    ~~~~~~~~~~~~~~~~^^
    14  File "/home/hodlinator/bc/3/test/functional/test_framework/test_framework.py", line 527, in start_nodes
    15    node.wait_for_rpc_connection()
    16    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
    17  File "/home/hodlinator/bc/3/test/functional/test_framework/test_node.py", line 316, in wait_for_rpc_connection
    18    raise FailedToStartError(self._node_msg(
    19        f'bitcoind exited with status {self.process.returncode} during initialization. {str_error}'))
    20test_framework.test_node.FailedToStartError: [node 0] bitcoind exited with status -6 during initialization. terminate called after throwing an instance of 'std::runtime_error'
    21  what():  Hello
    22************************
    

    Note how even the C++ exception message is now included.

  2. qa: Account for errno not always being set for ConnectionResetError
    Logging issue can be triggered by:
    
    ```diff
    --- a/src/httpserver.cpp
    +++ b/src/httpserver.cpp
    @@ -263,6 +263,7 @@ std::string RequestMethodString(HTTPRequest::RequestMethod m)
     /** HTTP request callback */
     static void http_request_cb(struct evhttp_request* req, void* arg)
     {
    +    throw std::runtime_error{"Hello"};
         evhttp_connection* conn{evhttp_request_get_connection(req)};
         // Track active requests
         {
    ```
    
    http.client.RemoteDisconnected not specifying errno to ConnectionResetError-ctor:
    https://github.com/python/cpython/blob/ce4b0ede16aea62ee7b1e02df7e1538102a356da/Lib/http/client.py#L1556C9-L1556C29
    76e0e6087d
  3. DrahtBot added the label Tests on Nov 14, 2025
  4. DrahtBot commented at 9:10 pm on November 14, 2025: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/33875.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK furszy, l0rinc

    If your review is incorrectly listed, please react with πŸ‘Ž to this comment and the bot will ignore it on the next update.

    LLM Linter (✨ experimental)

    Possible typos and grammar issues:

    • Work around issue where socket timeouts don’t have errno set. -> Work around an issue where socket timeouts don’t have errno set. [missing article “an” makes the sentence slightly ungrammatical]

    drahtbot_id_5_m

  5. in test/functional/test_framework/test_node.py:374 in 76e0e6087d
    373+                    if isinstance(e, TimeoutError):
    374+                        error_num = errno.ETIMEDOUT
    375+                    # http.client.RemoteDisconnected inherits from this type and
    376+                    # doesn't specify errno.
    377+                    elif isinstance(e, ConnectionResetError):
    378+                        error_num = errno.ECONNRESET
    


    furszy commented at 8:43 pm on November 15, 2025:

    nit: might want to update the line below to state this could also happen due to an uncaught exception at the server side. Talking about this:

    0errno.ECONNRESET, # This might happen when the RPC server is in warmup
    

    hodlinator commented at 1:10 pm on November 17, 2025:

    Will try to come up with something in case I re-touch. (Edit: ->) Something like:

    0errno.ECONNRESET,  # This might happen when the RPC server is in warmup, or throws an exception and disconnects us
    
  6. furszy commented at 8:55 pm on November 15, 2025: member

    Tested ACK 76e0e6087d0310ec31f43d751de60adf0c0a2faa

    Thanks for improving this. It makes understanding internal issues simpler.

    It’d be nice if the upcoming http server implementation caught these unhandled exceptions, writes to std::cerr and returns a proper error instead of exposing the internal one via the http response. Tagging @pinheadmz.

  7. l0rinc approved
  8. l0rinc commented at 6:16 pm on November 19, 2025: contributor

    untested code review ACK 76e0e6087d0310ec31f43d751de60adf0c0a2faa

    This is a continuation of https://github.com/bitcoin/bitcoin/pull/30660/files#diff-7f22a082e3a80ca2f212e36193f87dd80237035afedb7f15b116ef7fa265f3eeR326, separating the existing TimeoutError to add extra details for ConnectionResetError as well.


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2025-12-02 21:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me