{"record":{"id":"c8f269318d0a24e1","repo":"Hmbown/CodeWhale","slug":"error-additionally-could-not-verify-secret-stor","errorCode":null,"errorMessage":"{error}; additionally could not verify secret-store rollback for {slot}: {rollback}","messagePattern":"(.+?); additionally could not verify secret-store rollback for (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cli/src/lib.rs","lineNumber":2740,"sourceCode":"                    \"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.\",\n                    codewhale_config::quote_os_path(store.path())\n                ));\n            }\n        },\n        Err(error) => {\n            store.config = original_config;\n            return Err(anyhow::anyhow!(\n                \"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.\",\n                codewhale_config::quote_os_path(store.path())\n            ));\n        }\n    };\n    if let Err(error) = store.save() {\n        store.config = original_config;\n        if secret_store_saved {\n            let current = secrets\n                .get(slot)\n                .map_err(|rollback| anyhow::anyhow!(\n                    \"{error}; additionally could not verify secret-store rollback for {slot}: {rollback}\"\n                ))?;\n            if current.as_deref() == Some(api_key) {\n                match prior_secret.expect(\"snapshot succeeded before secret write\") {\n                    Some(previous) => secrets.set(slot, &previous),\n                    None => secrets.delete(slot),\n                }\n                .map_err(|rollback| anyhow::anyhow!(\n                    \"{error}; additionally failed to restore prior secret-store state for {slot}: {rollback}\"\n                ))?;\n            }\n        }\n        return Err(error);\n    }\n    codewhale_config::scrub_plaintext_api_keys_from_config_backup(store.path())?;\n    Ok(secret_store_saved)\n}\n","sourceCodeStart":2722,"sourceCodeEnd":2758,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/crates/cli/src/lib.rs#L2722-L2758","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: no preflight check, rollback read fails on a dead keyring\nlet secret_store_saved = match secrets.set(slot, api_key) { ... };\n// after: verify the backend is readable before starting the transaction\nsecrets.get(slot).map_err(|e| anyhow!(\"secret backend unavailable: {e}\"))?;\nlet secret_store_saved = match secrets.set(slot, api_key) { ... };","handlingStrategy":"try-catch","validationCode":"// Rust: preflight the secret backend and config writability before the transaction\nlet prior = secrets.get(slot).map_err(|e| anyhow!(\"secret backend unreadable: {e}\"))?;\nlet cfg_ok = store.path().parent().map(|p| p.exists()).unwrap_or(false);\nif !cfg_ok { anyhow::bail!(\"config directory missing; fix it before persisting keys\"); }","typeGuard":null,"tryCatchPattern":"// Rust\nmatch persist_provider_api_key(&mut store, &secrets, provider, &api_key) {\n    Ok(saved_to_store) => { /* proceed; plaintext key was scrubbed */ }\n    Err(e) if e.to_string().contains(\"could not verify secret-store rollback\") => {\n        // secret store state is unknown: inspect the slot with a keyring tool before retrying\n        eprintln!(\"secret store in unknown state: {e:#}\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["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."],"tags":["secret-store","keyring","rollback","config-save","rust"],"backgroundTag":"secret-store-rollback-failed","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}