Hmbown/CodeWhale · error
resolving external credential path
Error message
resolving external credential path: {err} What it means
This error wraps a failure of std::env::current_dir() while resolving a relative external credential path to an absolute one. The library deliberately avoids canonicalization (to not touch credential paths before consent or bless symlink targets), so it falls back to joining the current working directory. If the process's working directory cannot be determined (e.g. it was deleted), this error is thrown.
Solutions
- Pass an absolute path to resolve_external_credential_path instead of a relative one
- Restore or recreate the directory the process was started from, or chdir to a valid directory before calling
- Check that the process user has permission to stat the current directory
- Wrap the call in error handling that surfaces the underlying io::Error for diagnosis
Example fix
// before
resolve_external_credential_path("../secrets/key.toml")
// after
resolve_external_credential_path("/home/user/project/secrets/key.toml") Defensive patterns
Strategy: validation
Validate before calling
let p = std::path::Path::new(cred);
if !p.is_absolute() {
let cwd = std::env::current_dir().map_err(|e| format!("cwd unavailable: {e}"))?;
p = cwd.join(p);
} Try / catch
match resolve_external_credential_path(p) {
Ok(path) => use(path),
Err(e) => log::error!("credential path resolution failed: {e}"),
} Prevention
- Always pass absolute credential paths
- Resolve and cache current_dir() at startup, failing fast if unavailable
- Avoid launching from directories that may be deleted (e.g. temp dirs)
When it happens
Trigger: Calling resolve_external_credential_path (directly or via validate_read_scope / disclosed_paths_are_absolute_and_lexically_normalized_without_io) with a relative path while the process CWD no longer exists or current_dir() fails for OS reasons.
Common situations: Running the binary from a directory that was deleted after launch; launching from a removed tmp dir; containers/chroots with no accessible CWD; passing a relative credential path in scripts launched with unusual working directories.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- atomically replacing xAI OAuth credentials
- Codewhale-owned credential file must be singly linked
- Codewhale-owned credential file must be singly linked…
- external credential path contains a NUL byte
- external credential path must be absolute
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/86ca068711b1efc0.
Report an issue: GitHub.
Appendix: source
Thrown at crates/config/src/external_credentials.rs:113
| '\u{200f}'
| '\u{2028}'
| '\u{2029}'
| '\u{202a}'..='\u{202e}'
| '\u{2066}'..='\u{2069}'
)
}
/// Resolve a user-selected path without touching the filesystem.
///
/// Consent is bound to the exact logical path, so this intentionally avoids
/// canonicalization (which would stat the candidate before consent exists).
pub fn resolve_external_credential_path(path: impl AsRef<Path>) -> Result<PathBuf> {
let path = path.as_ref();
let absolute = if path.is_absolute() {
path.to_path_buf()
} else {
std::env::current_dir()
.map_err(|err| anyhow::anyhow!("resolving external credential path: {err}"))?
.join(path)
};
// Normalize only lexical `.` / `..` components. Canonicalization would
// inspect a credential path before consent exists and would also silently
// bless a symlink target. The secure reader rejects symlink/reparse-point
// components when the granted capability is actually consumed.
let mut normalized = PathBuf::new();
for component in absolute.components() {
match component {
Component::Prefix(prefix) => normalized.push(prefix.as_os_str()),
Component::RootDir => normalized.push(component.as_os_str()),
Component::CurDir => {}
Component::ParentDir => {
if !normalized.pop() {
bail!(
"external credential path escapes its absolute root: {}",
quote_os_path(&absolute)View on GitHub (pinned to 73e0f67d83)