Summary
bb status reports success against a daemon that is not running, and hangs with zero bytes against one that is stalled. Both builtins commonly reached for as a health check (bb status, bb plugin list) fail on the stalled case, while the plugin command path is the only surface that is self-describing when the daemon cannot answer the probe.
Correction (2026-08-25, see comment below): an earlier version of this sentence claimed the plugin path was bounded in every failure state. That is withdrawn — it generalised from a fixture that only stalled the probe. runPluginCliCommand's POST /api/v1/plugins/:id/cli has no timeout, so once the probe succeeds and the daemon stalls after it, bb tasks list also hangs with zero bytes. No bb command is bounded.
Measured on bb 0.39.0, macOS 15 (Darwin 25.5.0), 2026-08-25T06:45:20Z–06:46:37Z.
Reproduction
Point the CLI at a URL where nothing is listening:
BB_SERVER_URL=http://127.0.0.1:<closed-port> bb status
Expected: non-zero exit and an error saying bb is unreachable.
Actual: rc=0 in 0.22s, printing e.g. Project: proj_xxxxxxxxxx — values read from local config/env, with no connection ever made.
Full matrix
Three daemon states, exercised against a fake daemon so each state is controlled. n=10 for the hang cases.
| daemon state |
bb status |
bb plugin list |
bb tasks list (plugin path) |
| dead — nothing listening |
rc=0, 0.22s, prints project |
rc=1, 0.22s, Cannot connect to BB server |
rc=1, 0.21s, bb is not running at <url> |
| stalled — accepts, never answers |
hangs, 0 bytes, killed at 25s (10/10) |
hangs, 0 bytes, killed at 25s (10/10) |
rc=1, 10.85s, bb did not respond … after 3 attempts (last window 4000ms) |
| answering, broken |
rc=1, c.childThreads.map is not a function |
rc=1, Error: [ |
rc=1, unknown command 'tasks' |
Mechanism
Observed by logging the fake daemon's inbound requests:
bb plugin list issues one unbounded GET /api/v1/plugins — no AbortSignal, no timeout, no retry. A daemon that accepts the socket and never responds hangs the CLI indefinitely.
- The plugin command path issues three bounded
GET /api/v1/plugins/contributions (2s / 4s / 4s windows, with 150ms and 500ms backoff), then reports how many attempts it made.
So the retry work added for the plugin path (#1313) gave that path a property the builtins lack.
Why the rc=0 case matters most
bb status is widely treated as the safe liveness probe because it skips the plugin-contribution probe. That advice is in our own machine documentation, and we found it in 8 separate places including an installer's install-time health check on a fresh machine — which means an install can report bb healthy against no daemon at all.
An rc=0 that never touched the network is indistinguishable from a genuine success, so nothing downstream can detect it.
Suggested fixes, in the order we'd value them
bb status should fail non-zero when it cannot reach the daemon. If printing cached/local config without a connection is intentional, please make it explicit — a separate flag, or a line in the output stating the daemon was not contacted.
- Bound
bb plugin list's request with a timeout, so it errors rather than hanging.
- Optionally, document which commands actually contact the daemon. The builtin/plugin split does not currently predict it.
Workaround we adopted
timeout 20 bb plugin list — never bare, since unwrapped it hangs on exactly the condition you reach for it in. We removed bb status from our docs as a health probe entirely.
Happy to supply the fake-daemon harness used for the matrix if useful.
Summary
bb statusreports success against a daemon that is not running, and hangs with zero bytes against one that is stalled. Both builtins commonly reached for as a health check (bb status,bb plugin list) fail on the stalled case, while the plugin command path is the only surface that is self-describing when the daemon cannot answer the probe.Measured on bb 0.39.0, macOS 15 (Darwin 25.5.0), 2026-08-25T06:45:20Z–06:46:37Z.
Reproduction
Point the CLI at a URL where nothing is listening:
Expected: non-zero exit and an error saying bb is unreachable.
Actual:
rc=0in 0.22s, printing e.g.Project: proj_xxxxxxxxxx— values read from local config/env, with no connection ever made.Full matrix
Three daemon states, exercised against a fake daemon so each state is controlled.
n=10for the hang cases.bb statusbb plugin listbb tasks list(plugin path)rc=0, 0.22s, prints projectrc=1, 0.22s,Cannot connect to BB serverrc=1, 0.21s,bb is not running at <url>rc=1, 10.85s,bb did not respond … after 3 attempts (last window 4000ms)rc=1,c.childThreads.map is not a functionrc=1,Error: [rc=1,unknown command 'tasks'Mechanism
Observed by logging the fake daemon's inbound requests:
bb plugin listissues one unboundedGET /api/v1/plugins— noAbortSignal, no timeout, no retry. A daemon that accepts the socket and never responds hangs the CLI indefinitely.GET /api/v1/plugins/contributions(2s / 4s / 4s windows, with 150ms and 500ms backoff), then reports how many attempts it made.So the retry work added for the plugin path (#1313) gave that path a property the builtins lack.
Why the
rc=0case matters mostbb statusis widely treated as the safe liveness probe because it skips the plugin-contribution probe. That advice is in our own machine documentation, and we found it in 8 separate places including an installer's install-time health check on a fresh machine — which means an install can report bb healthy against no daemon at all.An
rc=0that never touched the network is indistinguishable from a genuine success, so nothing downstream can detect it.Suggested fixes, in the order we'd value them
bb statusshould fail non-zero when it cannot reach the daemon. If printing cached/local config without a connection is intentional, please make it explicit — a separate flag, or a line in the output stating the daemon was not contacted.bb plugin list's request with a timeout, so it errors rather than hanging.Workaround we adopted
timeout 20 bb plugin list— never bare, since unwrapped it hangs on exactly the condition you reach for it in. We removedbb statusfrom our docs as a health probe entirely.Happy to supply the fake-daemon harness used for the matrix if useful.