Hmbown/CodeWhale · error · anyhow::Error
Secret storage write failed for {slot}: {err}. Refusing to w
Error message
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. What it means
During migration of a provider API key from plaintext config into the secret store, the write secrets.set(slot, api_key) failed. Codewhale refuses the plaintext fallback by design: the in-memory config is restored and the error names the slot, the backend error, and the config path that was deliberately left unchanged.
Source
Thrown at crates/cli/src/lib.rs:2357
provider: ProviderKind,
api_key: &str,
) -> Result<bool> {
let original_config = store.config.clone();
prepare_provider_api_key_metadata(store, provider);
let slot = provider_slot(provider);
// A readable prior value is required before a secret-store write so a
// later config failure can restore the exact prior state. If the backend
// cannot provide that snapshot, fail before changing the config file.
let prior_secret = secrets.get(slot);
let secret_store_saved = match prior_secret.as_ref().map_err(|error| error.to_string()) {
Ok(_) => match secrets.set(slot, api_key) {
Ok(()) => {
clear_provider_api_key_from_config(store, provider);
true
}
Err(err) => {
store.config = original_config;
return Err(anyhow::anyhow!(
"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)View on GitHub (pinned to 8880682c63)
Solutions
- Unlock the keyring or start a secret service (gnome-keyring, kwallet) so writes succeed
- Switch the configured secret backend to one available in that environment and retry
- Rerun the same key-set command after the backend is fixed — the config was not modified, so the retry is clean
- Confirm no plaintext key was written anywhere; the refusal is intentional
Defensive patterns
Strategy: validation
Validate before calling
// Probe the secret backend with a throwaway slot before migrating real keys:
fn secrets_backend_ok(secrets: &codewhale_secrets::Secrets) -> bool {
let probe = format!("__probe_{}", std::process::id());
secrets.set(&probe, "x").is_ok() && { let ok = secrets.get(&probe).is_ok(); let _ = secrets.delete(&probe); ok }
} Prevention
- Ensure a secret service (gnome-keyring/kwallet) is running and unlocked on headless Linux before key setup
- Run `codewhale doctor` to check secret-backend health before migrating keys
- Never work around this by pre-writing the key into config as plaintext — the refusal exists to prevent that
When it happens
Trigger: Provider auth/key-set flows when the OS secret backend errors on write: locked keyring, missing secret-service/dbus on headless Linux, Windows Credential Manager unavailable, or a configured backend (CODEWHALE_SECRETS_BACKEND) that cannot persist.
Common situations: Headless Linux servers or containers without gnome-keyring/kwallet; keyring locked before login completes; full or corrupted credential store.
Related errors
- Secret storage snapshot failed for {slot}: {error}. Refusing
- No local {} API key was found in config, the secret store, o
- {error}; additionally could not verify secret-store rollback
- {error}; additionally failed to restore prior secret-store s
- unavailable credential
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/dc69dea3abff801d.
Report an issue: GitHub.