Skip to content

CLI-047: from systemd the secrets path reports a missing bw binary when the real cause is a locked vault #1237

Description

@mlorentedev

What happened

During CLI-042's post-deploy verification on msi, hive.service crash-looped. Its journal said, 34 times:

dotf[112172]: Error: bw resolve nan-api-key/api-key: bw item not found:
  bw get item "nan-api-key": exec: "bw": executable file not found in $PATH

The same command run from an interactive shell said something different:

Error: bw resolve nan-api-key/api-key: bitwarden vault is locked:
  no bw serve daemon is running — run `dotf secrets unlock` (not `bw unlock`, which
  only prints a session key to your shell and leaves this command's vault locked)

Same failure, same machine, same second. The only difference is the caller's PATH: bw lives in an nvm-managed directory (~/.nvm/versions/node/<ver>/bin) that a systemd --user unit does not inherit.

Why the difference matters

dotf secrets resolves over the bw serve daemon on loopback and falls back to the bw CLI. When the vault is locked, the daemon is absent, so resolution falls through to the CLI — and there the two contexts diverge:

  • interactive: bw is found, reports vault is locked, names the fix (dotf secrets unlock)
  • systemd: bw is not found, reports executable not found, names no fix

Only the first message is actionable. The second describes the fallback's own incidental problem and points at PATH, which is not the cause and whose repair would change nothing — once the vault is unlocked the daemon serves and the CLI is never consulted. Confirmed by consequence: after dotf secrets unlock, hive converged on the next retry with the PATH untouched.

ActiveState=active  SubState=running  Result=success
NRestarts=34 -> 34  (unchanged across a 40s window; RestartSec=30)

The misleading variant is the one that appears where no human is watching. A daemon's journal is read during an incident, by someone who does not yet know why it is down. This one sends them to fix a PATH that is not broken.

Measured cost: it produced a written finding asserting the drop-in's convergence design was defeated and would never converge, and the fix that finding implied — rendering the nvm bin directory into the unit's PATH at setup — would have added machinery to work around a problem that does not exist. Caught only by running the discriminating test instead of acting on the reconstruction.

What a fix looks like

The failure the user must act on is "the vault is locked", and dotf knows that before it ever tries the CLI — the serve daemon's absence is the thing it detected first. The CLI's exec error should not be able to displace it.

  1. Report the daemon-absent cause as primary, and demote the fallback's error to a detail. When the serve daemon is unreachable, say so and name dotf secrets unlock, regardless of how the fallback then fails.
  2. Treat "bw not on PATH" as its own diagnosable condition rather than an item-resolution error — the current text (bw item not found: ... executable file not found) claims an item lookup failed when no lookup happened.
  3. Optionally, have dotf doctor note that bw is absent from the systemd user PATH, so it is known before an incident rather than during one.

Acceptance

  • With the vault locked and bw off PATH, the error names the locked vault and dotf secrets unlock
  • The message is identical whether the caller is an interactive shell or a systemd unit, since the cause is
  • A genuine "bw missing" condition is still reported, but not as an item-resolution failure

Related: CLI-024 (bw serve backend), ADR-028, #1230 (the drop-in whose journal surfaced this).

Metadata

Metadata

Assignees

No one assigned

    Labels

    debtKnown tech-debt paydown

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions