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

ReviewabilityReviewsAgreementSize
#35902 chriszeng1010 zmq: Log bind error at Error level, abort startup on init errorWaiting on author0Mild70 + 43 tests
  • Prevent node operators from running unaware that ZMQ notifications failed to start
  • Abort startup with an explicit error when configured ZMQ sockets fail to bind or initialize
  • Ready for review
  • General agreement that ZMQ bind failures should abort startup loudly
  • Concept approval after testing with port conflicts and misconfigurations (pinheadmz)
  • Approach approval verified through broken-config startup tests (jeanpablojp)
  • Unaddressed objection: unnecessary intermediate helper function indirection, no author reply (pinheadmz)
  • 70 lines added or modified outside tests
  • 43 lines added or modified in tests
  • 44 lines removed in total
  • 9 files, 1 commits
RPC / REST / ZMQ#15 of 55
P3 · bug fix
  • P3 because node operators avoid running unaware that configured ZMQ notifications are disabled
  • Configuration mistakes and port conflicts are caught immediately at startup rather than swallowed
  • Ranking pass: Moved up 7: silently disabled ZMQ leaves downstream notification consumers blind, a bigger operational hazard than the other P3 diagnostics.
Reviewability: ReadyStalePaused
Agreement: StrongPositivePositive w/ caveatsNeutralMildDisputedBlockedCrickets
Reviews: current code-review ACKs, then (+stale ACKs) and -NACKs; greener = more ACKs.
Size: lines added or modified outside tests, then in tests; greener = smaller.

Goal

Refactors ZMQ initialization to return a util::Result with detailed failure messages across notifier setup, socket options, and binding. Propagates initialization failures to AppInitMain so that bitcoind logs an error and aborts startup via InitError if any configured ZMQ notifier fails to initialize.

Problem: When a node operator configures -zmqpub* options and a socket fails to bind (such as when the port is already taken or the address is invalid), bitcoind logs only to the debug log and continues running without ZMQ notifications. The operator is left unaware that notifications are disabled.

Evidence of importance:

  • Issue #33715 reported that binding failures when a port was in use were swallowed in debug logs, allowing bitcoind to start while getzmqnotifications showed nothing and the user was unaware.
  • The PR resurrects inactive PR #33727 to fulfill agreement from maintainers on #33715 that ZMQ bind failures should log loudly and abort startup.

Reviewability

Paused · Waiting on author

Open objection from pinheadmz with no author reply for 39 days; review would repeat what has been asked.

Waiting on (from the thread read):

  • author: respond to pinheadmz's inline review comment questioning the GetNotifiers intermediate function 2026-09-23

Agreement

Mild

objection that needs an answer has none yet (pinheadmz)

Thread notes: Added inline claim rc:4086226222 from pinheadmz questioning the need for GetNotifiers intermediate function. PR is now waiting on the author.

Objections, suggestions, and questions:

ReviewerTypeHarm, request, or questionStatusMust beAuthor repliedQuote
pinheadmz (member)objection, interfaceUsers are left without actionable debug information because the underlying bind error reason is not bubbled up to stdout upon startup failure.fixed · fix pushed · author refactored return type to util::Result · v1, not yet re-checkedansweredyes2026-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?'
Status from: 2026-08-07: chriszeng1010: 'I refactored the Initialize()'s return type to util::Result<void> and it returns the error code and failure reason.'
pinheadmz (member)objection, correctnessFunctional test used loose regex matching and missed testing failure cases like unavailable IP and port conflict with RPC.fixed · fix pushed · author added test cases and replaced regex with exact string matching · v1, not yet re-checkedansweredyes2026-08-12: 'Why use the regex here? You should be able to assert that the error is exactly this, right? ... Also I'd like to see a test covering the other expected errors'
Status from: 2026-08-17: chriszeng1010: 'Added new test cases and verified locally on Windows OS. Linux/MacOS are pending CI. I replaced the Regex with a string '
pinheadmz (member)objection, approachUnnecessary intermediate helper function and indirection in ZMQ notification initializationopen · v1, not yet re-checkedansweredno2026-09-23: 'I don't understand why you need this GetNotifiers intermediate function. I would just expect to see CZMQNotificationInterface::Create() return a Result bubbling up from CZMQNotificationInterface::Initialize()'

Support:

  • pinheadmz (member) (Concept ACK, 2026-08-06) [tested]: Built and tested locally with a variety of zmq misconfigurations, permissioned ports, busy ports, etc.
  • jeanpablojp (contributor) (Approach ACK, 2026-08-17) [both: interface_zmq.py]: Built and ran `interface_zmq.py`, plus some manual broken-config scenarios, and the abort works. Agree with pinheadmz's test coverage requests.

Participants:

  • sedited (member, neutral, 1 statements 2026-08-05 to 2026-08-05): asked author to drop a separate drive-by cleanup commit
  • pinheadmz (member, support, 4 statements 2026-08-06 to 2026-09-23): Concept ACK; suggested bubbling error reasons to stdout, adding test cases, and questioned intermediate GetNotifiers function
  • jeanpablojp (contributor, support, 1 statements 2026-08-17 to 2026-08-17): Approach ACK; verified interface_zmq.py and abort behavior, supported pinheadmz's test requests

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

The short text the ranking pass compares across PRs.

Bitcoin Core aborts startup with an explicit error message if any configured ZMQ notification socket fails to initialize or bind. Currently, if an operator configures -zmqpub* and binding fails due to an invalid address or an occupied port, bitcoind proceeds silently and only logs at debug level, leaving the operator unaware that ZMQ is inactive. Issue #33715 documented this silent failure when ports were already in use. Nodes without ZMQ options configured are unaffected.

Data

dossier JSON · extract JSON · model ledger, generated 2026-09-24T01:20, confidence high, input hash a6b42d977739925c
thread read through 2026-09-23 (12 statements), head 311847fffa
Discussion read under schema 1 rules: suggestions and questions may be missing, and an objection may combine several harms (schema history).
labels: RPC/REST/ZMQ

Categories

RPC / REST / ZMQ

P3 · bug fix (ranking pass: Moved up 7: silently disabled ZMQ leaves downstream notification consumers blind, a bigger operational hazard than the other P3 diagnostics.)

Prevents silent failure where bitcoind starts normally despite failing to bind configured ZMQ sockets. As noted in issue #33715, bind failures were previously swallowed in debug logs, leaving operators unaware that notifications were disabled.

Membership: Matches RPC/REST/ZMQ label and src/zmq/ paths, altering ZMQ notification initialization and error reporting.

Factors: security/stability 1, bug 2, performance 0, user value 2, leverage 0