Hmbown/CodeWhale · error

Codewhale credentials directory has an unsupported component

Error message

Codewhale credentials directory has an unsupported component: {}

What it means

open_owned_credentials_directory walks each component of the credentials directory path, opening pinned handles; only RootDir and Normal components are supported. Any other component kind (e.g. CurDir, ParentDir, or prefix components) is rejected because the store must pin real directory identity component by component.

Solutions

  1. Normalize the credentials directory path (canonicalize or strip `.`/`..`) before configuring it
  2. Set the credentials directory to a plain absolute path with only normal components
  3. Re-run with the corrected config value

Example fix

// before
let dir = PathBuf::from("/home/u/.config/../.codewhale/xai");
// after
let dir = PathBuf::from("/home/u/.codewhale/xai");
Defensive patterns

Strategy: validation

Validate before calling

fn has_only_normal_components(p: &std::path::Path) -> bool {
    p.components().all(|c| matches!(c, std::path::Component::Normal(_) | std::path::Component::RootDir))
}
assert!(has_only_normal_components(&creds_dir));

Type guard

fn has_only_normal_components(p: &std::path::Path) -> bool {
    p.components().all(|c| matches!(c, std::path::Component::Normal(_) | std::path::Component::RootDir))
}

Try / catch

match Store::open(dir) {
    Err(e) if e.to_string().contains("unsupported component") => {
        let dir = std::fs::canonicalize(dir)?;
        Store::open(dir)
    }
    other => other,
}

Prevention

When it happens

Trigger: Opening the credential store (Store::open) or logout cleanup when the configured credentials directory contains `.` or `..` or other non-Normal components.

Common situations: Config path built with relative segments like `../.codewhale` or `./creds`; Windows paths with unsupported prefix components; env-derived paths not cleaned before use.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

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

    // 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 {
            if matches!(component, Component::RootDir) {
                continue;
            }
            bail!(
                "Codewhale credentials directory has an unsupported component: {}",
                crate::quote_os_path(directory)
            );
        };
        let name = cstring_from_os_str(name)?;
        // SAFETY: parent borrowed from live `current`; `name` outlives the call.
        let mut fd = unsafe {
            libc::openat(
                std::os::fd::AsRawFd::as_raw_fd(&current),
                name.as_ptr(),
                libc::O_RDONLY | libc::O_DIRECTORY | libc::O_CLOEXEC | libc::O_NOFOLLOW,
            )
        };
        if fd < 0 && std::io::Error::last_os_error().kind() == std::io::ErrorKind::NotFound {
            // SAFETY: both the parent descriptor and component pointer remain
            // valid for this call. `mkdirat` cannot follow the missing leaf.
            let created = unsafe {
                libc::mkdirat(

View on GitHub (pinned to 73e0f67d83)