Hmbown/CodeWhale · error
; additionally could not verify secret-store rollback for
Error message
{error}; additionally could not verify secret-store rollback for {slot}: {rollback} What it means
This error is raised in `persist_provider_api_key_unlocked` (crates/cli/src/lib.rs:2740) when persisting a provider API key: the secret store write succeeded, but the subsequent config-file save failed, and while attempting to roll back the secret store the verification read (`secrets.get(slot)`) itself failed. It chains the original config-save error with the rollback-read failure so the developer knows the secret slot may still hold the new key and its prior state could not be confirmed. The library throws it because it refuses to silently leave the secret store in an unknown state after a partial transaction.
Solutions
- Check the chained `{rollback}` message for the secret-backend root cause (keyring unavailable, dbus session missing, permission denied) and fix that backend first.
- Fix the original `{error}` (config save failure) — check permissions/ownership and free space on the config file path reported elsewhere in the output.
- Re-run the command after the backend is healthy; the persist flow is idempotent and will re-write the key.
- If the slot still holds the new key and that is acceptable, manually restore the prior secret (e.g. `secret-tool` / keyring utility) or re-run the previous provider's auth to overwrite it.
Example fix
// before: no preflight check, rollback read fails on a dead keyring
let secret_store_saved = match secrets.set(slot, api_key) { ... };
// after: verify the backend is readable before starting the transaction
secrets.get(slot).map_err(|e| anyhow!("secret backend unavailable: {e}"))?;
let secret_store_saved = match secrets.set(slot, api_key) { ... }; Defensive patterns
Strategy: try-catch
Validate before calling
// Rust: preflight the secret backend and config writability before the transaction
let prior = secrets.get(slot).map_err(|e| anyhow!("secret backend unreadable: {e}"))?;
let cfg_ok = store.path().parent().map(|p| p.exists()).unwrap_or(false);
if !cfg_ok { anyhow::bail!("config directory missing; fix it before persisting keys"); } Try / catch
// Rust
match persist_provider_api_key(&mut store, &secrets, provider, &api_key) {
Ok(saved_to_store) => { /* proceed; plaintext key was scrubbed */ }
Err(e) if e.to_string().contains("could not verify secret-store rollback") => {
// secret store state is unknown: inspect the slot with a keyring tool before retrying
eprintln!("secret store in unknown state: {e:#}");
}
Err(e) => return Err(e),
} Prevention
- Run Codewhale inside a session that has a working, unlocked keyring (dbus session present).
- Verify the config file path is writable before running auth commands.
- Avoid running keyring-backed commands over bare SSH without dbus/keyring setup.
- Keep disk space above a safe margin where config and secret stores live.
When it happens
Trigger: Call the API-key persist flow (e.g. `codewhale` provider auth commands) where: (1) `secrets.set(slot, api_key)` succeeded, (2) `store.save()` returned Err (config file unwritable, disk full, permissions, invalid path), and then (3) `secrets.get(slot)` also returned Err during rollback verification.
Common situations: Headless/CI machines where the OS keyring (gnome-keyring, Windows Credential Manager, macOS Keychain) locked or the dbus session died between the set and the read; config file made read-only or its directory removed; disk-full during config save.
Related errors
- ; additionally failed to restore prior secret-store state…
- ; additionally failed to restore prior secret-store state…
- restoring retired xAI OAuth file
- A pinned task provider requires an explicit model
- Absolute path should not warn
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/c8f269318d0a24e1.
Report an issue: GitHub.
Appendix: source
Thrown at crates/cli/src/lib.rs:2740
"Secret storage write failed for {slot}: {err}. Refusing to write the API key in plaintext to {}. Fix the configured secret backend and retry; Codewhale did not change that file.",
codewhale_config::quote_os_path(store.path())
));
}
},
Err(error) => {
store.config = original_config;
return Err(anyhow::anyhow!(
"Secret storage snapshot failed for {slot}: {error}. Refusing to write the API key in plaintext to {}. Fix the configured secret backend and retry; Codewhale did not change that file.",
codewhale_config::quote_os_path(store.path())
));
}
};
if let Err(error) = store.save() {
store.config = original_config;
if secret_store_saved {
let current = secrets
.get(slot)
.map_err(|rollback| anyhow::anyhow!(
"{error}; additionally could not verify secret-store rollback for {slot}: {rollback}"
))?;
if current.as_deref() == Some(api_key) {
match prior_secret.expect("snapshot succeeded before secret write") {
Some(previous) => secrets.set(slot, &previous),
None => secrets.delete(slot),
}
.map_err(|rollback| anyhow::anyhow!(
"{error}; additionally failed to restore prior secret-store state for {slot}: {rollback}"
))?;
}
}
return Err(error);
}
codewhale_config::scrub_plaintext_api_keys_from_config_backup(store.path())?;
Ok(secret_store_saved)
}
View on GitHub (pinned to 433685b202)