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

  1. If the existing generation is current, no action needed — the token is already installed; just reload it
  2. If stale, remove or rename the existing credential file and retry the login/refresh
  3. Serialize concurrent CLI runs (or rely on the existing lock) so only one writer installs the generation
  4. 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

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


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)