Hmbown/CodeWhale · error · anyhow::Error
external credential path changed for {}; consent covers {},
Error message
external credential path changed for {}; consent covers {}, current path is {} What it means
Thrown by ExternalCredentialConsentToml::validate_read_scope (crates/config/src/external_credentials.rs:448) when the persisted read-only consent record pins a different absolute path than the credential path the caller currently resolves. Consent is deliberately scoped to one exact provider/source/path tuple, so any drift fails closed instead of silently granting read access to a new file. The record itself is untouched; only the capability check fails.
Source
Thrown at crates/config/src/external_credentials.rs:449
source.as_str()
);
}
if !self.path.is_absolute() {
bail!(
"external credential consent path for {} must be absolute",
provider.as_str()
);
}
let normalized = resolve_external_credential_path(&self.path)?;
if normalized != self.path {
bail!(
"external credential consent path for {} must be lexically normalized: {}",
provider.as_str(),
quote_os_path(&self.path)
);
}
if self.path != resolved_path {
bail!(
"external credential path changed for {}; consent covers {}, current path is {}",
provider.as_str(),
quote_os_path(&self.path),
quote_os_path(resolved_path)
);
}
Ok(())
}
/// Validate and mint the read capability consumed by credential adapters.
/// No filesystem operation occurs while validating the policy.
pub fn read_grant(
&self,
provider: ProviderKind,
source: ExternalCredentialSource,
resolved_path: &Path,
) -> Result<ExternalCredentialReadGrant> {
self.validate_read_scope(provider, source, resolved_path)?;View on GitHub (pinned to 0c42157ee5)
Solutions
- Re-run the consent flow for the provider so the record stores the current resolved path (after it, validate covers the new file)
- If the old file is still the intended one, point the source env var/config back to the consented path shown in the message (consent covers <old>, current path is <new>)
- Run `codewhale auth external-revoke --provider <provider>` if you want to clear the stale consent before re-consenting
- Check the consent status surface (ambient_path_changed field in ExternalCredentialConsentStatus) to confirm the drift before acting
Example fix
# before export MY_PROVIDER_CREDENTIALS=/home/me/creds/old-key.json # consent covers this mv /home/me/creds/old-key.json /home/me/creds/new-key.json # read_grant -> path changed for <provider> # after export MY_PROVIDER_CREDENTIALS=/home/me/creds/new-key.json codewhale auth external-revoke --provider <provider> # re-run the external-credential consent flow so consent covers new-key.json
Defensive patterns
Strategy: validation
Validate before calling
// before read_grant, compare the consent record path with the currently resolved path
let consent: &ExternalCredentialConsentToml = /* loaded */;
if consent.path != resolved_path {
// re-run the consent flow instead of calling read_grant
} Try / catch
match consent.read_grant(provider, source, &resolved_path) {
Ok(grant) => { /* use grant */ }
Err(e) if e.to_string().contains("external credential path changed") => { /* prompt re-consent */ }
Err(e) => return Err(e),
} Prevention
- Store the consent path next to the credential and alert when the source env var is repointed
- Surface the ambient_path_changed status flag in any UI that lists external credentials
- Revoke and re-consent as part of credential rotation runbooks
When it happens
Trigger: Calling validate_read_scope or read_grant with a resolved_path that differs from self.path (the absolute, lexically normalized consented path): the env var backing the credential source was repointed, the credential file was moved/renamed, HOME or the workspace changed the resolution, or the provider table was copied to another machine with different layout.
Common situations: Rotating service-account files (new filename, old consent), syncing dotfiles between machines, CI with a different HOME, re-arranging ~/.config or a credentials directory after running the consent flow once.
Related errors
- external credential path escapes its absolute root: {}
- external credential access is disabled for {}
- managed external credential access is unsupported for {}; no
- external credential consent for {} uses unsupported version
- external credential consent is scoped to provider {:?}, not
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/442e6974f098b88f.
Report an issue: GitHub.