#35902 zmq: Log bind error at Error level, abort startup on init error
https://github.com/bitcoin/bitcoin/pull/35902 · · +113/-44 in 9 files, 1 commits · labels: RPC/REST/ZMQ
Goal
- Prevent silent node startup when configured ZMQ notification endpoints fail to bind
- Alerts node operators and dependent services immediately instead of running without notifications
Aborts bitcoind initialization when configured ZMQ notification endpoints fail to bind or initialize, returning a detailed OS error string via util::Result and InitError. Replaces debug-level logs with Error-level startup failures and adds regression test coverage in interface_zmq.py for occupied ports, unreachable addresses, and invalid arguments.
Problem: When -zmqpub* options are supplied with invalid arguments, unavailable interfaces, or ports already bound by other processes, bitcoind previously logged only a debug message and continued starting. Operators and downstream services relying on ZMQ notifications received no events and had no visible indication that socket setup failed.
Category: RPC / REST / ZMQ (#27 of 52)
P3 · bug fix
- P3 because node operators avoid silent notification outages when endpoints fail to bind
- Protects dependent services that assume notifications are active whenever the node is up
P3 because it fixes an ongoing issue where ZMQ socket bind failures are silently swallowed into debug logs during startup (#33715). Operators running indexers or services dependent on ZMQ events are alerted immediately upon startup instead of silently losing notifications.
Membership: Modifies ZMQ notification initialization and error handling, covered under the RPC/REST/ZMQ domain.
Factors: security/stability 1, bug 1, performance 0, user value 1, leverage 0
Reviewability: Ready
- Ready for review with all reviewer feedback addressed and CI passing
The branch is clean and passing CI with all requested review feedback addressed.
Author status: active, waiting on reviewer feedback following updates on 2026-08-30
Resolved concerns:
- sedited asked to drop a separate cleanup commit, which the author squashed
- pinheadmz suggested propagating the specific bind error reason instead of a generic initialization failure, which the author implemented using util::Result
- pinheadmz requested explicit functional test assertions for specific error messages and failure cases including port collision with RPC, which the author added with platform-specific string handling
Agreement: Strong
- Strong support for aborting node startup on ZMQ bind errors
- Concept approval after testing broken configs and requesting error bubbling (pinheadmz)
- Approach approval after verifying startup abort behavior with broken configs (jeanpablojp)
Concept ACK and Approach ACK with manual testing; test feedback from pinheadmz was implemented
Both active reviewers tested the change and agreed with the concept and approach. All requested improvements regarding error text formatting and test coverage have been addressed.
- pinheadmz: 'Concept ACK. Built and tested locally with a variety of zmq misconfigurations'
- jeanpablojp: 'Approach ACK. Built and ran interface_zmq.py, plus some manual broken-config scenarios, and the abort works.'
Objections:
| Reviewer | Kind | Harm | Status | Blocking | Author replied | Quote |
|---|---|---|---|---|---|---|
| sedited | style | unnecessary separate commit changing names | resolved | no | yes | 2026-08-05: 'Can you drop the second commit? We don't typically change these names in separate drive-by commits.' Settled: 2026-08-05: chriszeng1010 squashed the commit and replied 'Okie. Done.' |
| pinheadmz | interface | failure to surface underlying OS errno reason in the startup error message left users without actionable debug info | resolved | no | yes | 2026-08-06: '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?' Settled: 2026-08-07: chriszeng1010 refactored Initialize to util::Result<void> returning zmq_strerror description |
| pinheadmz | correctness | test lacked exact message matching and missed failure modes like unavailable IP and port conflict with RPC | resolved | no | yes | 2026-08-12: 'Why use the regex here? You should be able to assert that the error is exactly this... Also I'd like to see a test covering the other expected errors' Settled: 2026-08-17: chriszeng1010 pushed tests asserting exact strings for EADDRNOTAVAIL and EADDRINUSE via rpc_port() |
Support:
- pinheadmz: tested locally with invalid and conflicting ZMQ configurations
- jeanpablojp: tested interface_zmq.py and verified that startup abort works as expected under broken configs
Participants: sedited (neutral), pinheadmz (support), jeanpablojp (support)
State derived from the lists: substantive support, no open objection (pinheadmz, jeanpablojp)
Review verdicts (DrahtBot): 0
- Approach ACK: jeanpablojp
- Concept ACK: pinheadmz
Files
45 lines under test/bench/ci.
- test/functional/interface_zmq.py +43/-2
- src/zmq/zmqnotificationinterface.cpp +25/-18
- src/zmq/zmqpublishnotifier.cpp +20/-16
- src/init.cpp +10/-2
- src/zmq/zmqnotificationinterface.h +8/-2
- src/zmq/zmqabstractnotifier.h +3/-1
- src/zmq/zmqutil.h +2/-1
- src/zmq/zmqpublishnotifier.h +1/-1
- src/zmq/zmqutil.cpp +1/-1
Card
PR #35902 ensures that bitcoind aborts initialization with a clear error message when configured ZMQ notification sockets fail to bind, addressing issue #33715 where such errors were previously hidden in debug logs while the node continued running. The patch refactors ZMQ notifier initialization to return util::Result containing the underlying OS socket error text and integrates with InitError in init.cpp. Functional tests in interface_zmq.py are expanded to verify exact error messages across different socket failure scenarios. The PR has Concept ACK and Approach ACK from pinheadmz and jeanpablojp with all review suggestions addressed, and it is ready for final review.