Hmbown/CodeWhale · error

refusing to replace an existing xAI OAuth generation

Error message

refusing to replace an existing xAI OAuth generation

What it means

Windows write_owned_file refuses to overwrite an existing generation when called with allow_replace=false (first-write semantics); the unix twin fails instead at linkat with EEXIST ("installing a new xAI OAuth generation without replacement"). The guard prevents a second login or refresh from silently clobbering credentials another flow just installed.

Source

Thrown at crates/config/src/xai_credentials.rs:956

            })();
            if let Err(error) = secured {
                let cleanup = mark_windows_file_handle_for_deletion(&file);
                return match cleanup {
                    Ok(()) => Err(error),
                    Err(cleanup) => Err(error).context(format!(
                        "also failed to delete the empty lifecycle lock: {cleanup:#}"
                    )),
                };
            }
            return Ok(file);
        }
        bail!("xAI OAuth lifecycle lock changed repeatedly while opening")
    }

    fn write_owned_file(&self, name: &str, bytes: &[u8], allow_replace: bool) -> Result<()> {
        let path = self.directory.join(name);
        if let Some(existing) = self.open_owned_file_for_read(name)? {
            anyhow::ensure!(
                allow_replace,
                "refusing to replace an existing xAI OAuth generation"
            );
            drop(existing);
        }
        let mut temporary = tempfile::NamedTempFile::new_in(&self.directory)
            .context("creating private xAI OAuth temporary file")?;
        let temporary_path = temporary.path().to_path_buf();
        let security_handle =
            reopen_windows_file_for_owner_security(temporary.as_file(), &temporary_path)?;
        secure_windows_owner_only_handle(&security_handle, false)
            .context("securing a new xAI OAuth temporary file before writing credentials")?;
        validate_owned_file_handle(&security_handle, &temporary_path)
            .context("verifying a new xAI OAuth temporary file before writing credentials")?;
        let write_result = (|| -> Result<()> {
            temporary
                .write_all(bytes)
                .context("writing xAI OAuth temporary file")?;

View on GitHub (pinned to 8880682c63)

Solutions

  1. If updating existing credentials is intended (token refresh), pass allow_replace=true
  2. If it must be a fresh install, first store.remove(name) or pick a new generation id and repoint the config
  3. Check existence first: store.read_to_string(name)? returning Some means you must decide replace vs abort
  4. In tests, use a fresh CODEWHALE_HOME per run

Example fix

// before
store.write(generation, &serialized, false)?; // fails when it already exists

// after
if store.read_to_string(generation)?.is_some() {
    store.write(generation, &serialized, true)?; // explicit refresh
} else {
    store.write(generation, &serialized, false)?; // first install
}
Defensive patterns

Strategy: validation

Validate before calling

// Decide replace semantics before writing
let exists = store.read_to_string(name)?.is_some();
anyhow::ensure!(
    allow_replace || !exists,
    "generation {name} already exists; pass allow_replace=true or pick a new id"
);

Try / catch

match store.write(name, &bytes, false) {
    Ok(()) => {}
    Err(e) if e.to_string().contains("refusing to replace an existing xAI OAuth generation") => {
        // deliberate refresh path
        store.write(name, &bytes, true)?;
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: store.write(name, bytes, false) when `name` already exists in $CODEWHALE_HOME/credentials: re-running codewhale auth xai-device against the same generation, a refresh racing an initial login, or tests replaying a write without clearing the directory.

Common situations: Retrying a partially failed device login; two concurrent logins converging on the same generation id; CI tests reusing one CODEWHALE_HOME across runs.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/e9ba9b0307ce9830. Report an issue: GitHub.