Hmbown/CodeWhale · error · anyhow::Error

xAI OAuth path must be a regular file

Error message

xAI OAuth path must be a regular file

What it means

validate_owned_file_handle runs on every opened credential file and on the lifecycle lock: after an O_NOFOLLOW open it verifies the inode is a regular file. Symlinks usually fail earlier with ELOOP at open time; this check catches FIFOs, sockets, devices, or a non-regular file substituted between open and metadata(), so tokens are never read from or written to special files.

Source

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

            )
        } != 0
        {
            return Err(std::io::Error::last_os_error()).context("retiring xAI OAuth file");
        }
        Ok(())
    }
}

#[cfg(unix)]
fn validate_owned_file_handle(file: &File, path: &Path) -> Result<fs::Metadata> {
    use std::os::unix::fs::MetadataExt as _;
    let metadata = file.metadata().with_context(|| {
        format!(
            "inspecting Codewhale-owned xAI OAuth file {}",
            crate::quote_os_path(path)
        )
    })?;
    anyhow::ensure!(metadata.is_file(), "xAI OAuth path must be a regular file");
    anyhow::ensure!(
        metadata.uid() == unsafe { libc::geteuid() },
        "xAI OAuth file must be owned by the current user"
    );
    anyhow::ensure!(
        metadata.nlink() == 1,
        "xAI OAuth file must not have multiple filesystem links"
    );
    Ok(metadata)
}

#[cfg(windows)]
fn open_owned_credentials_directory(directory: &Path) -> Result<XaiOAuthCredentialStore> {
    use std::os::windows::fs::OpenOptionsExt as _;
    use windows_sys::Win32::Storage::FileSystem::{
        FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT, FILE_GENERIC_READ,
        FILE_SHARE_READ, FILE_SHARE_WRITE, WRITE_DAC, WRITE_OWNER,
    };

View on GitHub (pinned to 8880682c63)

Solutions

  1. Inspect the entry: ls -l "$CODEWHALE_HOME/credentials" and look for type markers p, s, c, or b
  2. Remove the offending file: rm "$CODEWHALE_HOME/credentials/<name>", then re-run codewhale auth xai-device
  3. Find and stop whatever creates non-regular files there

Example fix

# before
ls -l "$HOME/.codewhale/credentials"
# prw-r--r-- 1 me me 0 xai-auth.json   (FIFO)

# after
rm "$HOME/.codewhale/credentials/xai-auth.json"
codewhale auth xai-device
Defensive patterns

Strategy: validation

Validate before calling

#[cfg(unix)]
fn is_plain_file(p: &std::path::Path) -> std::io::Result<bool> {
    let ft = std::fs::symlink_metadata(p)?.file_type();
    Ok(!ft.is_symlink() && ft.is_file())
}

Type guard

#[cfg(unix)]
fn credential_file_is_regular(dir: &std::path::Path, name: &str) -> bool {
    std::fs::symlink_metadata(dir.join(name))
        .map(|m| !m.file_type().is_symlink() && m.is_file())
        .unwrap_or(false)
}

Prevention

When it happens

Trigger: xai-auth.json, a generation file, or .xai-oauth.lock inside $CODEWHALE_HOME/credentials is a FIFO, unix socket, or device file; or the path is swapped for a non-regular file between the openat and the metadata call.

Common situations: Misconfigured dotfile tooling or pranks creating special files in the credentials directory; symlink-attack leftovers (these usually surface as the ELOOP open error instead); stale test fixtures.

Related errors


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