Hmbown/CodeWhale · error

xAI OAuth file must be owned by the current user

Error message

xAI OAuth file must be owned by the current user

What it means

The opened credential file must be owned by the current effective UID. Like the directory ownership check, this hardens against reading tokens planted or readable via another account's file, and complements the single-link and regular-file checks in validate_owned_file_handle.

Solutions

  1. Fix ownership: `sudo chown $(id -u):$(id -g) <credential file>` (and the parent directory).
  2. Re-authenticate so the store writes a fresh file owned by the current user.
  3. Avoid sudo for the CLI; copy credentials with correct ownership instead.
  4. In packaging/containers, ensure the credential provisioning step runs as the runtime UID.

Example fix

// shell fix
# sudo chown $(id -u):$(id -g) ~/.codewhale/xai.oauth.v1.json
// guard before calling
let md = std::fs::metadata(path)?;
anyhow::ensure!(md.uid() == unsafe { libc::geteuid() }, "token file not owned by current user");
Defensive patterns

Strategy: validation

Validate before calling

#[cfg(unix)]
fn file_owned_by_current_user(path: &Path) -> bool {
    use std::os::unix::fs::MetadataExt;
    std::fs::metadata(path).map(|m| m.uid() == unsafe { libc::geteuid() }).unwrap_or(false)
}

Prevention

When it happens

Trigger: validate_owned_file_handle (reached from read_to_string, write, remove, rename, open_internal_file, open_windows_file) finds metadata.uid() != geteuid() — e.g. the token file was written by root via sudo or restored from a root-owned backup.

Common situations: Running the app once as root created root-owned token files; rsync/tar restore preserved foreign ownership; a shared machine admin pre-populated credentials.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/15bb23ab0a182333. Report an issue: GitHub.

Appendix: source

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

        {
            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");
    // SAFETY: geteuid(2) dereferences no pointers.
    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 73e0f67d83)