Hmbown/CodeWhale · error
Secret storage failed: . Refusing to write the API key in…
Error message
Secret storage {operation} failed: {failure}. 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
Refusal guard against silently downgrading to a plaintext credential file. When the configured secret backend (keyring) fails for a save/delete operation, Codewhale would otherwise fall back to writing the API key into the config file; this error aborts instead and explicitly does not touch the config file.
Solutions
- Fix or unlock the OS secret backend (start `gnome-keyring`/`kwallet`, unlock the macOS login keychain, grant the terminal Keychain access)
- Retry the credential save once the backend works
- Set up a usable keyring environment (e.g. run under a session with a secret service) rather than relying on the plaintext file
- If credentials must be provided non-interactively, supply them via environment (`codex_credentials` env path) instead of the save routine
Defensive patterns
Strategy: validation
Validate before calling
let probe = keyring::Entry::new("codewhale", "probe");
if probe.and_then(|e| e.set_password("x")).is_err() {
anyhow::bail!("secret backend unavailable; fix keyring before saving");
} Try / catch
if let Err(e) = save_api_key(key) {
if e.to_string().contains("Refusing to write the API key in plaintext") {
// surface keyring setup instructions to the user
}
} Prevention
- Ensure a keyring/secret-service daemon runs in the environment (headless CI: use dbus + gnome-keyring)
- Unlock the OS keychain before automated credential operations
- Never rely on plaintext config fallback for API keys
When it happens
Trigger: Calling any credential save/delete path while the OS secret store is unavailable (keychain locked, `secret-service`/`keyring` crate backend error) and the code path that would otherwise write plaintext credentials to `config_path` is reached.
Common situations: Linux headless servers with no secret-service daemon; macOS keychain locked or access denied to the terminal app; Windows Credential Manager errors; keyring crate version changed its backend resolution.
Related errors
- bundle URLs may not include credentials
- Codewhale account login requires an OS credential manager…
- Codewhale-owned credential file DACL is not…
- Codewhale-owned credential file DACL must grant only one…
- Codewhale-owned credential file
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/e504b94962b1497f.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/config.rs:11982
},
Err(error) => Err(plaintext_credential_fallback_refused(
"snapshot", &path, &error,
)),
}
});
}
let path = save_api_key_to_config_file(trimmed)?;
codewhale_config::scrub_plaintext_api_keys_from_config_backup(&path)?;
Ok(SavedCredential::ConfigFile(path))
}
fn plaintext_credential_fallback_refused(
operation: &str,
config_path: &Path,
failure: &dyn std::fmt::Display,
) -> anyhow::Error {
anyhow::anyhow!(
"Secret storage {operation} failed: {failure}. 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(config_path)
)
}
/// The durable secret store for credential saves and logout-time deletes.
///
/// Under `cfg(test)` the store is only exposed when the test set both an
/// isolated `CODEWHALE_HOME` and an explicit backend, so unit tests can never
/// touch the developer's real credential store.
#[cfg(not(test))]
pub(crate) fn credential_secret_store() -> Option<codewhale_secrets::Secrets> {
Some(codewhale_secrets::Secrets::auto_detect())
}
#[cfg(test)]
pub(crate) fn credential_secret_store() -> Option<codewhale_secrets::Secrets> {
let isolated_home = codewhale_paths::codewhale_home_is_explicit();View on GitHub (pinned to 73e0f67d83)