Hmbown/CodeWhale · error

external credential path must resolve to an absolute path

Error message

external credential path must resolve to an absolute path: {}

What it means

Thrown by resolve_external_credential_path when, after lexically normalizing components, the resulting path is not absolute. The contract is that external credential sources must be absolute paths; relative paths are ambiguous because they would resolve against an unpredictable working directory, so the resolver rejects them outright.

Solutions

  1. Expand `~` and relative segments to a full absolute path before calling (e.g. use dirs::home_dir() or std::env::current_dir().join())
  2. Store absolute paths in the external credential source configuration
  3. On Windows include the drive letter (C:\...) in the configured path
  4. Use the canonicalized path from std::fs::canonicalize before handing it to the resolver

Example fix

// before
resolve_external_credential_path("~/secrets/token.txt")?;
// after
let home = std::env::var("HOME").unwrap();
resolve_external_credential_path(format!("{home}/secrets/token.txt"))?;
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_absolute(p: &std::path::Path) -> Option<std::path::PathBuf> {
    if p.is_absolute() { Some(p.to_path_buf()) }
    else { std::env::current_dir().ok().map(|d| d.join(p)) }
}
// expand '~' via home_dir() before resolving

Type guard

fn is_absolute_path(p: &str) -> bool { std::path::Path::new(p).is_absolute() }

Prevention

When it happens

Trigger: Passing a relative path such as "creds/token.txt" or "~/token" (tilde is not expanded by this function) to resolve_external_credential_path; on Windows, a path without a drive/prefix after normalization.

Common situations: Users typing relative paths into config for external credential sources; shell-style `~` paths pasted verbatim into configuration; scripts built from CWD-relative fragments.

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


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

Appendix: source

Thrown at crates/config/src/external_credentials.rs:139

    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)
                    );
                }
            }
            Component::Normal(part) => normalized.push(part),
        }
    }
    if !normalized.is_absolute() {
        bail!(
            "external credential path must resolve to an absolute path: {}",
            quote_os_path(&normalized)
        );
    }
    Ok(normalized)
}

/// The side-effect envelope Codewhale may use for an external credential.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ExternalCredentialAccess {
    /// Do not inspect or access the external credential store.
    #[default]
    Disabled,
    /// Read the exact selected file without refreshing or rewriting it.
    ReadOnly,
    /// Permit a documented preservation adapter to refresh and rewrite it.
    Managed,

View on GitHub (pinned to 73e0f67d83)