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
- Normalize the credentials directory path (canonicalize or strip `.`/`..`) before configuring it
- Set the credentials directory to a plain absolute path with only normal components
- 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
- Configure plain absolute paths for credential directories
- Strip `.`/`..` segments when deriving paths from env vars
- Test config paths on each target OS before shipping
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
- Runtime store root cannot contain '..' components
- append_allow_rules only accepts action = "allow"
- budget baseline_receipt path changed
- Codewhale credentials directory must be lexically normalized
- Codewhale terminal receipt exceeded its string bound
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(¤t),
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)