zmq: Log bind error at Error level, abort startup on init error #35902

pull chriszeng1010 wants to merge 1 commits into bitcoin:master from chriszeng1010:zmq-bind-abort changing 9 files +84 −44
  1. chriszeng1010 commented at 5:38 PM on August 5, 2026: none

    History

    This picks up #33727, which was closed for inactivity

    Problem

    Currently when a user configures -zmqpub* and the socket can't be bound, the program proceeds normally. The only trace is a debug-level log line that's invisible in a default configuration.

    #33715 hit this when their port was already taken.

    What this PR does

    The node refuses to start if ZMQ is configured and setup failed. This failure is now logged at error level.

    Code path: GetNotifiers builds the notifier objects from the config; Create initializes them — starts the ZMQ engine and binds each socket. When initialization fails, Initialize() returns false. Create() sees the result and returns nullptr. init.cpp sees it and returns InitError. On a node with no -zmqpub* option, the notifier list is empty.

    Why abort?

    #17445 fixed bitcoind crash from bad assert due to ZMQ config (issue #17185). Issue #33715 reports that when ZMQ port was already taken, bitcoind started but user could not see anything with getzmqnotifications. Maintainers at the time agreed it should log louder and abort at startup. Which is what this PR fixes.

    Testing

    bitcoind -regtest -zmqpubhashblock=foo Result: exits with code 1, and prints:

    [error] zmq: Failed to bind address, msg: Invalid argument Error: Initializing ZMQ interface failed.

    A node with no -zmqpub* options starts exactly as before — nothing changes for nodes that don't use ZMQ.

  2. DrahtBot added the label RPC/REST/ZMQ on Aug 5, 2026
  3. DrahtBot commented at 5:39 PM on August 5, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

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

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

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

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline and AI policy for information on the review process.

    Type Reviewers
    Concept ACK pinheadmz

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  4. sedited commented at 6:32 PM on August 5, 2026: contributor

    Can you drop the second commit? We don't typically change these names in separate drive-by commits.

  5. chriszeng1010 force-pushed on Aug 5, 2026
  6. chriszeng1010 commented at 6:38 PM on August 5, 2026: none

    Can you drop the second commit? We don't typically change these names in separate drive-by commits.

    Okie. Done.

  7. pinheadmz commented at 3:22 PM on August 6, 2026: member

    Concept ACK. Built and tested locally with a variety of zmq misconfigurations, permissioned ports, busy ports, etc.

    Before I review the code I just noticed that the error reason is not bubbled up to stdout, and I wonder if we can do that?

    Example: reason is "Failed to bind address, msg: Permission denied"

    --> bcd -regtest -zmqpubhashblock="tcp://127.0.0.1:80" -debug=zmq -printtoconsole=0
    Error: Initializing ZMQ interface failed.
    

    Example: reason is "Failed to bind address, msg: Address already in use"

    --> bcd -regtest -zmqpubhashblock="tcp://127.0.0.1:9050" -debug=zmq -printtoconsole=0
    Error: Initializing ZMQ interface failed.
    

    etc...

  8. chriszeng1010 force-pushed on Aug 7, 2026
  9. chriszeng1010 commented at 5:10 PM on August 7, 2026: none

    I refactored the Initialize()'s return type to util::Result<void> and it returns the error code and failure reason.

    Tested:

    $ mkdir -p /tmp/zmqcheck ./build/bin/bitcoind.exe -regtest -datadir="$(cygpath -m /tmp/zmqcheck)" -zmqpubhashblock=foo -printtoconsole=0 echo "exit code: $?" Error: Failed to bind address foo for pubhashblock: Invalid argument exit code: 1

  10. in test/functional/interface_zmq.py:189 in cdca6ca48b outdated
     183 | @@ -184,8 +184,10 @@ def setup_zmq_test(self, services, *, recv_timeout=60, sync_blocks=True, ipv6=Fa
     184 |      def test_basic(self, unix = False):
     185 |          self.log.info(f"Running basic test with {'ipc' if unix else 'tcp'} protocol")
     186 |  
     187 | -        # Invalid zmq arguments don't take down the node, see #17185.
     188 | -        self.restart_node(0, ["-zmqpubrawtx=foo", "-zmqpubhashtx=bar"])
     189 | +        # Invalid zmq arguments should cause exit with an error
     190 | +        self.stop_node(0)
     191 | +        self.nodes[0].assert_start_raises_init_error(extra_args=["-zmqpubrawtx=foo", "-zmqpubhashtx=bar"])
    


    pinheadmz commented at 6:14 PM on August 7, 2026:

    Now that you've got the error messages spitting out, can we cover a few specifically with the functional test? See how other tests add expected_msg to this check


    chriszeng1010 commented at 8:50 PM on August 11, 2026:

    ack.

  11. chriszeng1010 force-pushed on Aug 11, 2026
  12. chriszeng1010 commented at 8:47 PM on August 11, 2026: none

    Latest push should fix broken CI. Added expected_msg to existing test cases, plus a secondary case with different notifier type.

  13. Log ZMQ bind error at Error level, abort startup on ZMQ init error
    Co-authored-by: Ash Manning <10554686+A-Manning@users.noreply.github.com>
    Co-authored-by: Chris Zeng <chris.dz@gmail.com>
    97c7f61fb7
  14. chriszeng1010 force-pushed on Aug 11, 2026
  15. in test/functional/interface_zmq.py:193 in 97c7f61fb7
     190 | +        # Invalid zmq arguments should cause exit with an error naming the notifier and address
     191 | +        self.stop_node(0)
     192 | +        self.nodes[0].assert_start_raises_init_error(
     193 | +            extra_args=["-zmqpubrawtx=foo", "-zmqpubhashtx=bar"],
     194 | +            expected_msg="Error: Failed to bind address bar for pubhashtx: .+",
     195 | +            match=ErrorMatch.PARTIAL_REGEX,
    


    pinheadmz commented at 3:19 PM on August 12, 2026:

    Why use the regex here? You should be able to assert that the error is exactly this, right?

    Error: Failed to bind address foo for pubrawblock: Invalid argument

    Also I'd like to see a test covering the other expected errors:

    (IP not available locally) Error: Failed to bind address tcp://1.2.3.4:100 for pubrawblock: Can't assign requested address

    (Port in use already by RPC -- will need to use rpc_port() in the test framework) Error: Failed to bind address tcp://127.0.0.1:18443 for pubrawblock: Address already in use


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: 2026-08-14 17:51 UTC

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