Hmbown/CodeWhale · error · anyhow::Error
installing a new xAI OAuth generation without replacement
Error message
installing a new xAI OAuth generation without replacement
What it means
The no-clobber variant of the same credential writer: when allow_replace=false, persist_noclobber() installs a new OAuth generation only if the destination does not already exist. On failure the io error is wrapped with 'installing a new xAI OAuth generation without replacement'. The dominant cause is EEXIST/AlreadyExists — the generation file is already there — i.e. a concurrent writer or a stale file from a previous run.
Solutions
- If the existing generation is current, no action needed — the token is already installed; just reload it
- If stale, remove or rename the existing credential file and retry the login/refresh
- Serialize concurrent CLI runs (or rely on the existing lock) so only one writer installs the generation
- Check parent-directory write permissions
Example fix
// before mv credentials.json credentials.json.bak && codewhale login // after (only if stale) rm ~/.codewhale/xai/credentials.json && codewhale login
Defensive patterns
Strategy: try-catch
Validate before calling
// check the generation file does not already exist before a no-clobber install
if path.exists() {
eprintln!("generation already installed at {} — reload or remove it first", path.display());
} Try / catch
match write_owned_file(&path, bytes, AllowReplace::No) {
Err(e) if is_already_exists(&e) => {
// concurrent install won the race; treat as success and reload
reload_credentials(&path);
}
r => r,
} Prevention
- Use a process lock around OAuth refresh so only one writer installs a generation
- Clean stale generation files after crashes before re-running login
- Point the CLI at a single consistent home directory to avoid name collisions
When it happens
Trigger: write_owned_file called with allow_replace=false and the target path already exists, or the parent directory is unwritable; concurrent logins racing to install the same generation.
Common situations: Two CLI instances refreshing xAI OAuth tokens simultaneously; leftover credential file from a crashed run; wrong home dir causing a name collision.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- atomically replacing xAI OAuth credentials
- refusing to replace xAI OAuth generation
- agy OAuth token JSON carries no access token member
- agy OAuth token member
- bearer credentials are not an API key
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/38560e7deeb6307a.
Report an issue: GitHub.
Appendix: source
Thrown at crates/config/src/xai_credentials.rs:1147
Err(error) => {
let tempfile::PersistError { error, file } = error;
let persistence_error = anyhow::Error::new(error)
.context("atomically replacing xAI OAuth credentials");
let error = cleanup_windows_secret_after_error(
&security_handle,
persistence_error,
"temporary file",
);
drop(file);
return Err(error);
}
}
} else {
match temporary.persist_noclobber(&path) {
Ok(file) => file,
Err(error) => {
let tempfile::PersistError { error, file } = error;
let persistence_error = anyhow::Error::new(error)
.context("installing a new xAI OAuth generation without replacement");
let error = cleanup_windows_secret_after_error(
&security_handle,
persistence_error,
"temporary file",
);
drop(file);
return Err(error);
}
}
};
if let Err(error) = validate_persisted_windows_owned_file(&persisted, &path) {
// MoveFileEx has already published this exact object. Delete it by
// handle rather than trusting the pathname again. For a refresh
// replacement this can leave the unchanged config pointer missing;
// that fail-closed availability outcome is safer than retaining a
// generation that failed the post-publication invariant check.
return Err(cleanup_windows_secret_after_error(View on GitHub (pinned to 73e0f67d83)