Findings

What the 102 records say about stability bugs in libmultiprocess and Bitcoin Core's IPC code. Every number comes from the verified records; the explorer lets you slice them, and the method page says how they were built. Counts depend on how bugs are split into records: counted differently, the total is anywhere from 94 to 104.

In short

What the bugs are

The failures are fail-stop. Of 102 records, 87 are crashes, asserts, hangs, deadlocks, data races or undefined behavior, and three more are IPC listeners that stop accepting connections for good. Only one describes the node silently doing the wrong thing: submitSolution accepting a block whose coinbase commitment was never rechecked.

Symptom Records Symptom Records
crash 37 fd leak 4
assert 15 timeout 3
hang 11 listener stops accepting 3
data race 10 out of memory 2
deadlock 7 wrong result 2
undefined behavior 7 leak 1

About half of them involve tearing something down. Of the 82 production defects, 42 are triggered by a disconnect, a shutdown or a signal. The most common trigger, in 17 production defects, is a client going away uncleanly: a process killed in a test, a Rust or Python client closing its socket without calling destroy, or an operator pressing Ctrl-C. All 17 are in server code. The share of disconnect bugs is falling, from 11 of 13 production records first reported in 2024 to 17 of 41 in 2026, but the number is not.

The root causes come down to a few sentences:

By record count the root causes are: an assumption violated 27, a lifetime error 16, an unhandled exception 13, an ordering error 13, a missing lock 8, and smaller groups. By side, 48 production defects are in server code, 10 in client code, 11 in both, 7 in the event loop and 5 in process spawning.

Old code, new exposure

First reported before 2024 2024 2025 2026 (to mid-October)
All records 9 13 32 48
Production defects 7 13 21 41

The count by year measures how hard the code was being exercised, not how old it was. Of the 73 production defects whose introducing commit is known, 37 date from the library's first commits in June to August 2019. Eighteen of the 41 production defects found in 2026 had been in the code for seven years. From the merge that introduced a bug to the merge that fixed it, the median was 996 days, and 31 of 63 lasted more than three years.

What changed was the workload. Reading each record's account of what exposed it gives a sequence, and each step was followed within weeks by a burst of two to six records:

When New workload Example
2024-05 A functional test kills the node under a live wallet process wallet hangs after node is killed
2024-08 A multi-connection test for -ipcbind stale connection pointer
2024-10 Long-blocking mining calls, Ctrl-C on a waiting client segfault on disconnect during a call
2024-12 A Rust client shutdown hangs while a client is connected
2025-06 Disconnect tests and a TSan job in the library's CI request-thread deadlock
2025-09 A Python test client and a fuzzer two requests on one thread
2025-10 v30.0 ships bitcoin-node; Stratum v2 software uses it crash after a killed client's waitNext returns
2026-01 Antithesis getParams() after cancel
2026-07 Server-side connect and listen tests, the Windows port ConnectStream use-after-free
2026-08 Code review, some of it LLM-assisted, and private security reviews disconnect handler after Connection destroyed

At the start of 2024, 41 production defects already in the code had not been reported. At the start of 2026, 28 had not.

Cumulative records over time, by first report and by fix

How long each defect was in the code before its fix

How they were found

Detection shifted twice: from people to tools, then to review.

Production defects, first found by people CI failure sanitizer new test review Antithesis or fuzzer
to mid-2024 8 2 0 0 0 0
2024, second half 6 1 2 1 0 0
2025, first half 4 0 4 0 1 0
2025, second half 5 2 1 2 1 1
2026, first half 0 3 2 0 4 2
2026, second half 2 2 0 4 20 2

Through 2025 most production defects were found by someone running the software: the maintainer, reviewers testing branches, a Rust client developer, Stratum v2 operators after v30.0. In 2026 only two were, both by developers testing the unmerged pull request that serves the Chain interface over IPC.

Sanitizer finds came in two bursts tied to new CI jobs: MSan and UBSan on the IPC unit tests in late 2024 (a downcast in a constructor), and the library's own TSan jobs in 2025. Antithesis is the first finder of three records and appears in six. What it added was a reproducible trace of a rare interleaving, and its finds were real: the getParams() use-after-free also crashed a Rust client three weeks later.

Review found 20 of the 30 production defects first reported since July 2026. Nineteen of the 24 found by review in 2026 have a report that says, or reads as if, an LLM helped; 18 came from the private security reviews. Across all report entries, none in 2024 and 1 of 53 in 2025 are marked LLM-assisted, against 42 of 88 in 2026. Most of these marks are judgments of writing style, so the trend is firmer than any single one.

The 2026 reviews also brought a kind of testing the history barely had: fault injection, forcing an allocation, a thread start or a system call to fail at a chosen point to see what the error path does. Thirteen of the audit reports rely on it. Six describe hardening only, because nothing but the injected failure reaches the code, and four became low-confidence records whose trigger is a failure that rarely happens on its own. Three are real stability bugs: a listener that stops for good after one failed accept(), a terminate when a signal interrupts the wait for a spawned process, and the client hang when building a request throws, which an earlier report had already found.

First detection method by quarter

How fast they were fixed

Once a bug was recognized, work started fast: the median bug waited 1 day for a fix PR and 8 more days for it to merge. Tool-found bugs closed fastest.

First found by Median days from report to merged fix
TSan or MSan 5
review 18
intermittent CI failure 25
user report 53.5
manual testing 188

The long tail, 17 bugs over 90 days, is mostly branch effects. Two wallet-process bugs reported in 2020 waited 1992 days for the branch that fixed them to merge (Ctrl-C reaches the wallet process), and the Windows socketpair hang waited a year for the Windows port.

Fixes got smaller as the design settled. The early fixes restructured: giving every proxy its own reference to the event loop, evicting clients at shutdown. Later ones mostly moved a lock or reordered two steps inside those mechanisms, such as the one-call prefetch that closed an Antithesis race. Among production fixes, new code paths and refactors were 5 of 21 in 2025 and 1 of 20 in 2026, and the median fix fell from 24 lines to 10. The median merged production fix is about 17 lines; 25 of the 69 merged fixes are under 10. Two recent fixes are the exceptions and the largest in the set: request cancellation (267 lines, February 2026) and disconnect-then-drain at shutdown (288 lines, pending). Small fixes do not mean small bugs: a one-line lock move can close a window a few instructions wide in code that ships in every release.

Eleven production defects were introduced by the fix for another record. The cancellation path produced three found within three weeks of merging (lock missing on cancel, getParams() after cancel, cancel callback after finish). The 2024 thread map fix led to a deadlock eleven months later and a thread-exit race a year after that.

Days from first report to fix

What it takes to trigger them

The libmultiprocess C++ client is methodical. It never abandons a request, never disconnects before calling destroy, and shuts down in order. A C++ peer used as designed can trigger 70 of the 82 production defects, cannot trigger 11, and for one it is unknown. For many of the 70 that means the peer being killed in the middle of a long call.

The eleven that need a foreign or misbehaving peer are of two kinds:

Rust and Python clients appear in the peer list of 23 production records.

Seen, or only possible

A record's symptom says what the code can do, which is often worse than what anyone saw. Of the 82 production defects, 9 were seen failing in production: in a node or GUI built from merged code and run by a person. Another 20 were seen failing only in a node, wallet or GUI built from an unmerged branch, such as the multiprocess wallet and GUI branches, mining branches or the Windows port. 47 were seen only in tests or under tools, and 6 never. Ten of the 47 were never more than a sanitizer report. Fifteen records needed a sanitizer or Antithesis to be seen at all, and ten are theoretical: found by reading code and never triggered outside analysis.

In September 2026 the open findings from the security reviews were tested against Bitcoin Core master. All seven bug records tried were reproduced, four of which had been theoretical: a client hang, a crash after destroy, a use-after-free during destroy and a leaked descriptor. The same tests showed that Bitcoin Core master still has the older, wider form of a socket leak fixed in libmultiprocess, until its subtree is updated. Each bug page has a Reproduction section.

Where they lived

Reports from the field

Eight records have reports from real deployments. All eight are in the mining interface, and all were hit by Stratum v2 software. None is in the wallet or GUI. Seven were in released binaries, and two are still open.

The most-reported bugs are the costly ones: the event loop relocking after exit was seen five times on three platforms over ten months. Fifty-seven bugs were reported once, 30 twice, 15 three or more times.

Test, CI and build problems

Twenty records are not production defects. They are the cost of the tools that found the others, and they arrive right after new tests: five from the library's sanitizer CI work in 2025, four from the Python functional tests, others from new spawn, connect and concurrency tests. One test race, a lost wake-up in the simultaneous-calls test, hung CI intermittently for six months. Thirty-nine records have at least one CI-failure report. The fix PRs drew 527 force-pushes and 2061 comments from people.

The waves idea

The survey started from a guess that the bugs came in five waves, each exposed once the previous class was handled: missing disconnect handling; unclean disconnects from aborting peers and non-C++ clients; racy disconnects needing new code paths; small leftover fixes, with a server-side sub-wave; and rare or theoretical races found by assisted review and Antithesis.

Two independent readings of the data reach the same verdict. What holds:

What does not hold:

The picture that replaces the waves is the exposure sequence above: each new workload reached code that had been there since 2019.

What is still open

How sure these numbers are

Confidence is high for 68 records, medium for 19 and low for 15. The most cautious view, leaving out marginal and low-confidence records, has 83 records and 68 production defects. First-report dates can come years before the fix work started. Three pairs of records share one report, which double-counts the delay of one event. The security-review findings that became bug records by September 2026 have all been reproduced (one only under ThreadSanitizer). The eleven added in October 2026 rest on the reviewers' own tests and analysis, which the survey has not repeated, and most of the other audit reports have not been tested, and the LLM-assistance marks are mostly judgments of style. Method details lists the remaining doubts.