Hmbown/CodeWhale · error · anyhow::Error
external credential consent is scoped to provider {:?}, not
Error message
external credential consent is scoped to provider {:?}, not {} What it means
Consent records are scoped to exactly one provider; validate_read_scope() compares the stored provider string against the requested ProviderKind and bails when a consent minted for one provider is presented for another. This prevents reusing one provider's file-based credential grant to authorize reads for a different provider.
Source
Thrown at crates/config/src/external_credentials.rs:421
"external credential access is disabled for {}",
provider.as_str()
);
}
if self.access == ExternalCredentialAccess::Managed {
bail!(
"managed external credential access is unsupported for {}; no schema-safe preservation adapter is available",
provider.as_str()
);
}
if self.consent_version != EXTERNAL_CREDENTIAL_CONSENT_VERSION {
bail!(
"external credential consent for {} uses unsupported version {}; revoke and consent again",
provider.as_str(),
self.consent_version
);
}
if self.provider != provider.as_str() {
bail!(
"external credential consent is scoped to provider {:?}, not {}",
self.provider,
provider.as_str()
);
}
if self.source != source {
bail!(
"external credential consent source mismatch for {} (expected {})",
provider.as_str(),
source.as_str()
);
}
if !self.path.is_absolute() {
bail!(
"external credential consent path for {} must be absolute",
provider.as_str()
);
}View on GitHub (pinned to 0c42157ee5)
Solutions
- Create a separate consent for each provider that should read that file
- Fix the provider field in the existing consent to match the provider being authenticated
Example fix
# before [[external_credentials]] provider = "acme" # ... later used to auth 'contoso' # after [[external_credentials]] provider = "acme" path = "/keys/acme.env" [[external_credentials]] provider = "contoso" path = "/keys/contoso.env"
Defensive patterns
Strategy: validation
Validate before calling
if consent.provider != provider.as_str() {
// wrong grant: look up (or create) the consent scoped to this provider
consent = find_consent(provider, source, &path).ok_or(missing_consent)?;
} Type guard
fn matches_provider(consent: &ExternalCredentialConsent, provider: ProviderKind) -> bool {
consent.provider == provider.as_str()
} Try / catch
match consent.validate_read_scope(provider, source, &path) {
Ok(()) => read_external_credential(&path),
Err(e) if e.to_string().contains("scoped to provider") => {
// per-provider grant model: consent again for this provider
consent_for(provider, source, &path).await
}
Err(e) => Err(e),
} Prevention
- Create one consent block per provider; never reuse or copy without editing provider
- After provider renames across versions, re-create consents
- Key consent lookups by (provider, source), not by path alone
When it happens
Trigger: validate_read_scope(provider_b, ...) is called with a consent record whose `provider` field is "provider-a" — e.g. config reuses/copies a consent block but the code path now requests a different provider kind.
Common situations: Copy-pasting a consent block in config when adding a second provider and forgetting to update the provider field; provider renames changing ProviderKind::as_str() between versions; tooling that looks up 'any' consent rather than the provider-specific one.
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 source mismatch for {} (expected
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/621c0891340a01d2.
Report an issue: GitHub.