Hmbown/CodeWhale · error · anyhow::Error

xAI OAuth credentials directory must be absolute

Error message

xAI OAuth credentials directory must be absolute

What it means

The unix open_owned_credentials_directory requires an absolute directory because it walks every component with openat(2) starting from '/'. The public path (xai_oauth_credentials_dir -> lexical_absolute_path) always absolutizes first, so this fires only when the opener is called directly with a relative path (in-crate tests or refactors that bypass XaiOAuthCredentialStore::open).

Source

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

}

fn validate_private_basename(name: &str) -> Result<()> {
    let path = Path::new(name);
    anyhow::ensure!(
        path.components().count() == 1
            && matches!(path.components().next(), Some(Component::Normal(_)))
            && path.file_name().and_then(|value| value.to_str()) == Some(name),
        "xAI OAuth private basename must be one UTF-8 path component"
    );
    Ok(())
}

#[cfg(unix)]
fn open_owned_credentials_directory(directory: &Path) -> Result<XaiOAuthCredentialStore> {
    use std::os::fd::FromRawFd as _;
    use std::os::unix::fs::{MetadataExt as _, PermissionsExt as _};

    anyhow::ensure!(
        directory.is_absolute(),
        "xAI OAuth credentials directory must be absolute"
    );
    // SAFETY: the literal root path contains no interior NUL and the returned
    // descriptor is immediately owned by `File`.
    let root_fd = unsafe {
        libc::open(
            c"/".as_ptr(),
            libc::O_RDONLY | libc::O_DIRECTORY | libc::O_CLOEXEC | libc::O_NOFOLLOW,
        )
    };
    if root_fd < 0 {
        return Err(std::io::Error::last_os_error()).context("opening filesystem root");
    }
    // SAFETY: `root_fd` is a newly owned descriptor on the success path above.
    let mut current = unsafe { File::from_raw_fd(root_fd) };
    for component in directory.components() {
        let Component::Normal(name) = component else {

View on GitHub (pinned to 8880682c63)

Solutions

  1. Join the path against std::env::current_dir() or codewhale_config::codewhale_home() before opening
  2. Use the public entry points (XaiOAuthCredentialStore::open / with_xai_oauth_lifecycle_lock), which absolutize for you

Example fix

// before
open_owned_credentials_directory(Path::new(".codewhale/credentials"))?;

// after
let dir = codewhale_config::codewhale_home()?.join("credentials");
assert!(dir.is_absolute());
open_owned_credentials_directory(&dir)?;
Defensive patterns

Strategy: validation

Validate before calling

anyhow::ensure!(
    dir.is_absolute(),
    "credentials directory must be absolute, got {}",
    dir.display()
);

Prevention

When it happens

Trigger: Direct calls such as open_owned_credentials_directory(Path::new("credentials")) from unit tests or new code; a refactor that skips lexical_absolute_path when computing the directory.

Common situations: Crate-internal tests constructing stores from relative tempdir paths; refactoring that calls the opener directly instead of through the public open().

Related errors


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