Hmbown/CodeWhale · error · anyhow::Error

external credential path must resolve to an absolute path: {

Error message

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

What it means

After component-wise normalization of a credential path, the result must still be absolute. The check catches prefix forms that are not true absolute paths (e.g. Windows drive-relative 'C:creds' — a prefix with no RootDir) or other malformed inputs whose normalized form loses its root, so the granted capability cannot be a well-defined absolute file.

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 0c42157ee5)

Solutions

  1. Write the path fully absolute, including the root: 'C:\\keys\\acme.env' rather than 'C:keys\\acme.env'
  2. On Windows, prefer paths produced by canonical absolute joiners (or copy the path from Explorer) when creating the consent

Example fix

# before
C:keys/acme.env   # drive-relative, normalizes non-absolute

# after
C:\keys\acme.env   # prefix + root + components
Defensive patterns

Strategy: validation

Validate before calling

// Require a truly absolute path up front (catches Windows drive-relative forms):
fn is_true_absolute(p: &std::path::Path) -> bool {
    p.is_absolute() // on Windows this requires prefix AND root, e.g. C:\\...
}
assert!(is_true_absolute(&consent.path));

Type guard

fn is_absolute_normalized(p: &Path) -> bool {
    p.is_absolute() && p.components().all(|c| !matches!(c, Component::CurDir | Component::ParentDir))
}

Try / catch

match resolve_external_credential_path(&p) {
    Ok(n) => n,
    Err(e) if e.to_string().contains("must resolve to an absolute path") => {
        reject_consent_input("rewrite as C:\\dir\\file or /dir/file")
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: resolve_external_credential_path() is called with a path whose components rebuild into a relative result — classically a Windows drive-relative path like 'C:keys\acme.env' (volume prefix present but no root), or unusual prefix combinations that strip the root during normalization.

Common situations: Windows paths pasted without the backslash after the colon; tools that emit drive-relative paths based on the process's per-drive current directory; scripted consent creation joining prefix + relative remainder incorrectly.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/c5b8ff6049ef40bf. Report an issue: GitHub.