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

  1. Create a separate consent for each provider that should read that file
  2. 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

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


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