Hmbown/CodeWhale · error

Secret storage snapshot failed for

Error message

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.

What it means

Before mutating the secret store, `set_provider_api_key_unlocked` snapshots the slot's prior value. If the snapshot read itself fails, it rolls back the in-memory config and returns this error rather than proceeding without a known prior state — the API key is never written in plaintext to the config file.

Solutions

  1. Fix backend availability (unlock keychain / start the secret service) and retry.
  2. Check read permissions on the secret backend for the current user.
  3. The config file is unchanged; simply re-run the command once the backend responds.
Defensive patterns

Strategy: try-catch

Try / catch

match set_provider_api_key(provider, key) {
    Err(e) if e.to_string().starts_with("Secret storage snapshot failed") => {
        eprintln!("Secret backend unreadable; unlock it and retry. Nothing was changed.");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling `set_provider_api_key` when the secret backend's initial `get(slot)` (snapshot) fails, before any secret write occurs.

Common situations: Keychain/session unavailable, backend permissions denied on read, or secret service crashed between operations.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/91bc320a377be65a. Report an issue: GitHub.

Appendix: source

Thrown at crates/config/src/credentials.rs:120

    // 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.",
                    crate::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.",
                crate::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),
                }

View on GitHub (pinned to 73e0f67d83)