Skip to content

fix(desktop): explain and record a fatal keyring failure at startup - #5986

Open
Chessing234 wants to merge 3 commits into
block:mainfrom
Chessing234:fix/keyring-full-startup-diagnostic
Open

fix(desktop): explain and record a fatal keyring failure at startup#5986
Chessing234 wants to merge 3 commits into
block:mainfrom
Chessing234:fix/keyring-full-startup-diagnostic

Conversation

@Chessing234

Copy link
Copy Markdown
Contributor

Addresses suggestions 2 and 3 of #5956.

A full Windows Credential Manager fails CredWriteW with error code 8, ERROR_NOT_ENOUGH_MEMORY — which reads like the machine is out of RAM and means nothing of the sort: the store will not accept another entry. It isn't Buzz-specific either; cmdkey /generic:test /user:test /pass:test fails identically on an affected machine.

Two things made that nearly undiagnosable:

The message was wrong. "Retry once the keyring is reachable" is incorrect in every particular here — the keyring is reachable, VaultSvc is running, and no amount of retrying or rebooting changes the outcome. keyring_failure_advice now recognises this failure and returns advice a user can act on; every other error returns None and keeps the existing wording, which is right for the transient cases.

The message was invisible. buzz-desktop.exe is a GUI-subsystem binary, so it has no console: the reason went to a stderr handle that doesn't exist, no crash dump was written (it's a deliberate exit, not a crash), and no log was left behind. The window flashed and the app was gone. The same message is now written to startup-error.log in the app data directory, next to the identity file it failed to read. All of it is best-effort — a failure to write the log must not replace the original error.

Deliberately not done: suggestion 1, falling back to the still-present identity.key instead of terminating. That trades a storage guarantee for availability, and the migration deletes identity.key on success precisely so the key lives in one place — reversing that is the maintainers' call, not a drive-by. Suggestion 4 (the misleading wording) is covered by the first commit.

I can't run Windows here, so the classification is pinned by unit tests against the exact strings from the report rather than by reproducing the failure.

Verified locally on the pinned 1.95.0 toolchain:

  • cargo test --manifest-path desktop/src-tauri/Cargo.toml --lib2445 passed, 0 failed (2440 before, plus the 5 new)
  • cargo clippy --manifest-path desktop/src-tauri/Cargo.toml --all-targets -- -D warnings — clean
  • cargo fmt --manifest-path desktop/src-tauri/Cargo.toml --all -- --check — clean

Note: I'm an outside contributor, so the workflow runs here sit at action_required until a maintainer approves them; only the DCO check reports on its own.

A full Windows Credential Manager fails `CredWriteW` with error code 8,
`ERROR_NOT_ENOUGH_MEMORY` — which reads like the machine is out of RAM and
means nothing of the sort: the store will not accept another entry. It is not
Buzz-specific; `cmdkey /generic:test /user:test /pass:test` fails identically
on an affected machine (block#5956).

Buzz's existing wording, "retry once the keyring is reachable", is wrong for
this case in every particular. The keyring is reachable, `VaultSvc` is
running, and no amount of retrying or rebooting will change the outcome.

`keyring_failure_advice` recognises that failure and returns advice a user can
act on. Everything else returns `None`, keeping the existing wording where it
is right.

No call sites yet.

Signed-off-by: Taksh <takshkothari09@gmail.com>
`buzz-desktop.exe` is linked as a GUI-subsystem binary on Windows, so it has
no console. When identity resolution fails the process prints its reason to a
stderr handle that does not exist and exits — the window flashes and the app
is gone, with no crash dump (it is a deliberate exit, not a crash) and no log.
From the user's side the app simply died after an update, and antivirus is
the natural and wrong suspect.

Write the same message to `startup-error.log` in the app data directory, next
to the identity file it failed to read, and route it through
`fatal_identity_message` so a full credential store arrives with the advice
that actually resolves it.

Everything here is best-effort: a failure to write the log must not replace
the original error.

This does not change the exit policy. block#5956 also asks that a failed keyring
write fall back to the still-present `identity.key` rather than terminate;
that trades a storage guarantee for availability and is the maintainers' call,
not a drive-by.

Signed-off-by: Taksh <takshkothari09@gmail.com>
@Chessing234
Chessing234 requested a review from a team as a code owner August 15, 2026 20:20

@themiguelamador themiguelamador left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found three release-blocking diagnostic issues and prepared a verified fix in https://github.com/Complear/buzz/tree/review/pr-5986-fix (commit 2ef74a8143b6929e24e207016dc19299124826b3).

  1. desktop/src-tauri/src/secret_store.rs: the classifier treated any identity-resolution error containing Windows error code 8 / ERROR_NOT_ENOUGH_MEMORY as a full Credential Manager, even for keyring reads or identity-file failures. That can prescribe deleting credentials for an unrelated failure. The fix requires keyring-write or CredWrite context and adds negative cases for read, entry, and file errors.

  2. desktop/src-tauri/src/secret_store.rs: the advice string contains large runs of literal spaces, so the user-facing startup log is malformed. The fix composes the text with deliberate single spaces and asserts the complete message.

  3. desktop/src-tauri/src/lib.rs: startup-error.log survives after identity resolution later succeeds. The stale fatal reason can then misdiagnose a later launch. The fix retires the file after successful identity resolution, reports non-NotFound cleanup errors, and covers the lifecycle with a regression test.

Verification: cargo fmt --check; focused classifier and startup-log tests; full Tauri library suite (2446 passed, 15 ignored); cargo clippy --workspace --all-targets -- -D warnings.

Review found three problems with the diagnostic these commits added.

**The advice fired on the wrong failures.** It matched the Windows error code
anywhere in the message, but `secret_store` produces `keyring read:`,
`keyring entry:`, `keyring get:` and `keyring unavailable:` alongside
`keyring write:`, and an identity *file* error can carry `os error 8` too.
The advice tells the user to delete credentials, so prescribing it for a read
sends them to destroy data over an unrelated failure. It now requires a
refused write, with negative cases pinning the read, entry, get, unavailable
and file paths.

**The advice was malformed.** A line-continued literal left runs of padding
mid-sentence, so the log line a user is meant to read came out with fourteen
spaces between clauses. Composed with `concat!` and deliberate single spaces,
and a test asserts the exact string and that it contains no double space.

**The log outlived the failure.** `startup-error.log` was written on the fatal
path and never removed, so once identity resolution succeeded a stale fatal
reason sat beside a working install, ready to misdiagnose the next launch.
`clear_startup_error_log` retires it on success — missing file is success,
anything else is reported, since a file that cannot be removed keeps
misleading. The filename is now one constant shared by both paths.

Signed-off-by: Taksh <takshkothari09@gmail.com>
@Chessing234

Copy link
Copy Markdown
Contributor Author

all three confirmed and fixed in 832b1413. i couldn't cherry-pick 2ef74a8143bhttps://github.com/Complear/buzz 404s for me on both git ls-remote and the api, so it's private or gone. implemented independently.

1. over-broad classifier. yours, and it's the worst of the three: the advice tells the user to delete credentials. secret_store emits keyring read:, keyring entry:, keyring get: and keyring unavailable: alongside keyring write:, and an identity-file error can carry os error 8 too, so a read failure would have sent someone to destroy data over something unrelated. now requires a refused write (keyring write / credwrite), with negative cases pinning read, entry, get, unavailable and the file path.

2. malformed advice. confirmed — the literal had fourteen spaces between clauses:

"...will not accept another entry.              Remove unused entries under..."

a line-continued literal that i never actually printed. composed with concat! and single spaces; a test asserts the exact string and that it contains no double space.

3. stale log. confirmed — i wrote startup-error.log on the fatal path and never removed it, so after a successful resolution a stale fatal reason sat next to a working install. clear_startup_error_log retires it on success: missing file is success, anything else is reported, since a file that can't be removed keeps misleading. filename is one shared constant now, and the lifecycle has a regression test (absent → written → cleared → idempotent).

verification: cargo test --manifest-path desktop/src-tauri/Cargo.toml --lib 2448 passed / 0 failed / 15 ignored, 6 focused tests in that module, cargo clippy --manifest-path desktop/src-tauri/Cargo.toml --all-targets -- -D warnings clean, cargo fmt clean.

separately: i've corrected my earlier claim on #5998 and #6001 that this machine had no dart/flutter. it does — hermit pins both — and i'm now running the mobile checks myself rather than leaning on your verification.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants