Hmbown/CodeWhale · error · anyhow::Error
xAI OAuth lifecycle lock was poisoned
Error message
xAI OAuth lifecycle lock was poisoned
What it means
with_xai_oauth_lifecycle_lock first takes a process-wide std::sync::Mutex to serialize xAI OAuth mutations inside the process, then a cross-process fd-lock on the lock file. This error means the in-process Mutex was poisoned: a previous holder panicked while holding it, so lock() returned Err. The poison is per-process; a fresh process acquires cleanly, and on-disk state stays consistent because the file lock serializes across processes.
Source
Thrown at crates/config/src/xai_credentials.rs:130
}
pub fn legacy_xai_oauth_path() -> Result<PathBuf> {
Ok(xai_oauth_credentials_dir()?.join(LEGACY_XAI_OAUTH_FILE_NAME))
}
/// Serialize every Codewhale-owned xAI OAuth lifecycle mutation across threads
/// and processes while pinning the lexical credentials directory.
///
/// Lock order is always xAI lifecycle first, then config document. Callers must
/// not invoke this function recursively.
pub fn with_xai_oauth_lifecycle_lock<T>(
operation: impl FnOnce(&XaiOAuthCredentialStore) -> Result<T>,
) -> Result<T> {
static PROCESS_LOCK: OnceLock<Mutex<()>> = OnceLock::new();
let _process_guard = PROCESS_LOCK
.get_or_init(|| Mutex::new(()))
.lock()
.map_err(|_| anyhow::anyhow!("xAI OAuth lifecycle lock was poisoned"))?;
let store = XaiOAuthCredentialStore::open()?;
let lock_file = store.open_lock_file()?;
let mut lock = fd_lock::RwLock::new(lock_file);
let _guard = lock.write().with_context(|| {
format!(
"failed to acquire xAI OAuth lifecycle lock in {}",
crate::quote_os_path(store.directory())
)
})?;
operation(&store)
}
/// Run an authority mode switch while the prior owned OAuth epoch is hidden
/// from concurrent Codewhale readers. A failed authority mutation restores the
/// old files; a successful mutation permanently removes them.
pub fn with_xai_oauth_revocation_transaction<T>(
operation: impl FnOnce() -> Result<T>,
) -> Result<T> {View on GitHub (pinned to 8880682c63)
Solutions
- Restart the process; the poison clears on restart
- Look earlier in the logs for the panic that poisoned the lock; that panic is the real bug, report it
- Do not delete credential files to fix this; the fd-locked on-disk state was protected across the panic
Defensive patterns
Strategy: try-catch
Try / catch
Map this Err to a 'restart required' signal: the poison is process-local, so spawn a fresh process or disable xAI operations for this session instead of retrying in-process. Pair it with a log scan for the original panic.
Prevention
- In long-lived hosts, run each xAI lifecycle operation in a short-lived subprocess so a panic cannot poison the host
- Report the underlying panic found earlier in the logs; the poison is only the symptom
- Never 'fix' it by deleting credential files: the fd-lock kept on-disk state consistent
When it happens
Trigger: Any panic inside the xAI OAuth lifecycle operation (or between acquisition and release) in this process; every subsequent with_xai_oauth_lifecycle_lock call in the same process then fails with this message.
Common situations: A long-lived process (daemon, test harness) where an earlier xAI login/logout/token-refresh panicked; later xAI operations all report the poisoned lock although the credential files on disk are fine.
Related errors
- Codewhale-owned xAI OAuth file {} is not valid UTF-8
- refusing oversized xAI OAuth credential payload
- xAI OAuth credentials not found. Options: 1. Run `codewhale
- MCP OAuth setup cancelled after plugin authority changed
- parallel(): expected an array of thunks
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/d2e0fad1dc51f5e8.
Report an issue: GitHub.