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

  1. Fix or unlock the OS secret backend (start `gnome-keyring`/`kwallet`, unlock the macOS login keychain, grant the terminal Keychain access)
  2. Retry the credential save once the backend works
  3. Set up a usable keyring environment (e.g. run under a session with a secret service) rather than relying on the plaintext file
  4. 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

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


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)