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

  1. Pass an absolute path to resolve_external_credential_path instead of a relative one
  2. Restore or recreate the directory the process was started from, or chdir to a valid directory before calling
  3. Check that the process user has permission to stat the current directory
  4. 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

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


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)