Hmbown/CodeWhale · error
external credential path changed for
Error message
external credential path changed for {}; consent covers {}, current path is {} What it means
Thrown by `ExternalCredentialConsentToml::validate_read_scope` when the consent record's path no longer equals the currently resolved credential path — the file the consent covers has moved, been replaced by a symlink, or been renamed since consent was given. The grant is invalidated rather than silently following the new location.
Solutions
- Revoke the old consent and re-consent against the credential's current location.
- Restore the credential file to the path covered by the existing consent (or fix the symlink).
- If a migration moved credential paths intentionally, re-run the consent flow as part of the migration.
Example fix
// before: consent covers old path after file moved mv ~/.codewhale/creds/google.json ~/secrets/google.json // after: point the credential back or re-consent ln -s ~/secrets/google.json ~/.codewhale/creds/google.json # or revoke + re-consent
Defensive patterns
Strategy: validation
Validate before calling
fn consent_covers_current_location(consent: &ExternalCredentialConsentToml) -> anyhow::Result<bool> {
Ok(resolve_external_credential_path(&consent.path)? == consent.path)
} Try / catch
match store.read_grant(provider, source, &path) {
Err(e) if e.to_string().contains("path changed") => {
// credential moved since consent: revoke and re-consent at the new location
store.revoke(provider)?;
run_consent_flow(provider)?;
}
other => other,
} Prevention
- Keep credential files at stable paths; move files only with a re-consent step.
- After any credential migration or upgrade, re-run the consent flow.
- Warn users not to rename or move consented credential files.
When it happens
Trigger: Calling `read_grant` where `resolved_path` (freshly resolved at read time) differs from `self.path` recorded at consent time — e.g. the credential file was moved, renamed, or is now reached via a different symlink.
Common situations: User moved/rotated their credential file after consenting; the credential store migrated from one location to another in an upgrade; a symlink target changed.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- external credential consent path for
- external credential consent path for
- external credential consent for
- external credential consent is scoped to provider
- external credential consent source mismatch for
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/442e6974f098b88f.
Report an issue: GitHub.
Appendix: source
Thrown at crates/config/src/external_credentials.rs:410
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 73e0f67d83)