Hmbown/CodeWhale · error
Codewhale credentials directory cannot be a volume root
Error message
Codewhale credentials directory cannot be a volume root
What it means
When walking the directory's components to open an owned handle per component, the handle list must be non-empty; an empty list means the path was a volume root (e.g. `C:\` or `/`), which has no per-component handle to secure. Using a volume root as the credential store would give the ownership/DACL guarantees nothing to scope to, so it is refused.
Solutions
- Point the store at a real subdirectory (e.g. `/home/user/.codewhale/xai`, not `/` or `C:\` )
- Fix the config/env value or the join logic that produced a bare root path
- Create the intended credentials subdirectory before opening the store
Example fix
// before
let dir = PathBuf::from("C:\\");
// after
let dir = PathBuf::from("C:\\Users\\me\\.codewhale\\xai"); Defensive patterns
Strategy: validation
Validate before calling
fn ensure_not_volume_root(dir: &std::path::Path) -> Result<(), String> {
let mut comps = dir.components();
if comps.next().is_some() && comps.next().is_none() {
return Err(format!("{} is a volume root; use a subdirectory", dir.display()));
}
Ok(())
} Try / catch
ensure_not_volume_root(&dir)?; std::fs::create_dir_all(&dir)?; let store = XaiCredentialStore::open(&dir)?;
Prevention
- Point the store at a dedicated subdirectory like ~/.codewhale/xai, never `/` or `C:\`
- create_dir_all the target before opening the store
- Validate configured paths at config-load time
When it happens
Trigger: Calling open with the path reduced to a root component — `Path::new("/")`, `Path::new("C:\\")`, or a UNC share root like `\\server\share` — after lexical normalization strips CurDir/ParentDir components.
Common situations: A config file or env var set to a drive root or `/`; a path-joining bug that dropped all subdirectories; accidentally passing `home_dir()` that resolved to `/` in a container.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- external credential path must resolve to an absolute path
- agent profile path is not a directory
- Codewhale credentials directory must be lexically normalized
- CODEWHALE_HOME / user home is unavailable
- Codewhale-owned xAI OAuth path has the wrong filesystem type
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/3783dc3611fc11f3.
Report an issue: GitHub.
Appendix: source
Thrown at crates/config/src/xai_credentials.rs:967
.read(true)
.share_mode(FILE_SHARE_READ | FILE_SHARE_WRITE)
.custom_flags(FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT);
let handle = options.open(¤t).with_context(|| {
format!(
"opening Codewhale credentials directory component {}",
crate::quote_os_path(¤t)
)
})?;
validate_windows_handle_path(&handle, ¤t, true)?;
handles.push(handle);
}
Component::CurDir | Component::ParentDir => bail!(
"Codewhale credentials directory must be lexically normalized: {}",
crate::quote_os_path(directory)
),
}
}
anyhow::ensure!(
!handles.is_empty(),
"Codewhale credentials directory cannot be a volume root"
);
let mut secure_options = fs::OpenOptions::new();
secure_options
.access_mode(FILE_GENERIC_READ | WRITE_DAC | WRITE_OWNER)
.share_mode(FILE_SHARE_READ | FILE_SHARE_WRITE)
.custom_flags(FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT);
let final_directory = secure_options.open(directory).with_context(|| {
format!(
"opening Codewhale credentials directory for owner-only security: {}",
crate::quote_os_path(directory)
)
})?;
validate_windows_handle_path(&final_directory, directory, true)?;
secure_windows_owner_only_handle(&final_directory, true)
.context("securing Codewhale credentials directory for the current user")?;
verify_windows_owner_only_handle(&final_directory)View on GitHub (pinned to 73e0f67d83)