{"record":{"id":"4abaf5c13d4fe98f","repo":"Hmbown/CodeWhale","slug":"restoring-retired-xai-oauth-file-original","errorCode":null,"errorMessage":"restoring retired xAI OAuth file {original}","messagePattern":"restoring retired xAI OAuth file (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/config/src/xai_credentials.rs","lineNumber":522,"sourceCode":"}\n\nimpl XaiOAuthRevocation {\n    /// Restore the old epoch after a config mutation fails. Restoration is\n    /// fail-closed: an unexpected replacement at an original name is never\n    /// overwritten.\n    pub fn rollback(self, store: &XaiOAuthCredentialStore) -> Result<()> {\n        #[cfg(windows)]\n        {\n            let _ = store;\n            Ok(())\n        }\n        #[cfg(not(windows))]\n        {\n            let mut first_error = None;\n            for (original, tombstone) in self.retired.into_iter().rev() {\n                let result = store.rename_raw(&tombstone, &original).with_context(|| {\n                    format!(\n                        \"restoring retired xAI OAuth file {}\",\n                        crate::quote_os_path(&store.directory.join(original))\n                    )\n                });\n                if result.is_err() && first_error.is_none() {\n                    first_error = result.err();\n                }\n            }\n            if let Some(error) = first_error {\n                return Err(error);\n            }\n            Ok(())\n        }\n    }\n\n    /// Permanently remove retired bytes after the replacement config commits.\n    pub fn commit(self, store: &XaiOAuthCredentialStore) -> Result<usize> {\n        let mut removed = 0;\n        for (_original, _tombstone) in self.retired {","sourceCodeStart":504,"sourceCodeEnd":540,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/config/src/xai_credentials.rs#L504-L540","documentation":"anyhow error raised by `XaiOAuthRevocation::rollback` (crates/config/src/xai_credentials.rs:522) when restoring a retired xAI OAuth file from its tombstone name back to the original name fails during `store.rename_raw(&tombstone, &original)`. Rollback is fail-closed: it never overwrites a file that unexpectedly appeared at the original name, and it keeps the first error while attempting every restoration. Called by `stage_revocation` and `mark_running_if_pending_with` when a config mutation fails and the old epoch must come back.","triggerScenarios":"The tombstone file was deleted or locked between retirement and rollback; another process created a file at the original path so the rename is refused (fail-closed); the credentials directory lost write permission mid-operation; on Windows the rollback path is a no-op, so this only fires on non-Windows stores.","commonSituations":"Two Codewhale/xAI CLI sessions racing on the same credentials directory; AV or sync tools (Dropbox, OneDrive) holding locks on the OAuth files; disk-full or permission changes between revocation staging and failure-driven rollback; stale tombstones left by a crashed prior run.","solutions":["Inspect the credentials directory (`store.directory`) for stray files at both the original and tombstone names; resolve the collision manually before retrying (move the unexpected file aside).","Close other Codewhale/xAI sessions and file-locking sync clients, then retry the operation.","Fix directory permissions (ensure the store directory is writable by the current user) and free disk space if exhausted.","After manual cleanup, re-run the credential revocation flow; rollback is idempotent per remaining tombstone and reports only the first failure."],"exampleFix":"// before (failed)\nrollback(store)?; // error: restoring retired xAI OAuth file /home/me/.codewhale/xai.oauth\n// after: clear the collision first\n// mv /home/me/.codewhale/xai.oauth /home/me/.codewhale/xai.oauth.unexpected\nrollback(store)?;","handlingStrategy":"try-catch","validationCode":"// before staging revocation\nlet dir = &store.directory;\nfor original in originals {\n    ensure!(!dir.join(original).exists(), \"unexpected file at {} blocks rollback\", dir.join(original).display());\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = revocation.rollback(&store) {\n    log::error!(\"xAI OAuth rollback failed: {e:#}; manual cleanup of {} required\", store.directory.display());\n    // surface to user; do not silently proceed with half-restored credentials\n}","preventionTips":["Avoid concurrent Codewhale/xAI sessions sharing one credentials directory.","Exclude the credentials directory from file-sync/AV scanning to avoid rename locks.","Verify directory writability and free disk space before credential mutations.","Clean stale tombstones from crashed runs before re-running revocation."],"tags":["filesystem","oauth","credentials","rollback","rename"],"backgroundTag":"file-not-found","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T16:17:23.217Z"}