Hmbown/CodeWhale · error

external credential access for

Error message

external credential access for {} is dormant until that provider is explicitly selected

What it means

External credential import (e.g. reading a credential from another tool's keychain/file) is gated on the provider it belongs to being the currently selected `api_provider`. If a caller requests an external credential grant for a provider that is not active, the access is refused as 'dormant' — the credential would be read but never used, so the read is denied rather than performed.

Solutions

  1. Set the provider you are importing credentials for as the active `api_provider` in config, then retry the import.
  2. Only request the external credential grant for `self.api_provider()`'s value — gate the call on that equality.
  3. If you need credentials for multiple providers, import each one in a run where that provider is selected.

Example fix

// before
let grant = cfg.external_credential_grant(ApiProvider::Google, source, &path)?; // active is openai

// after
if provider == cfg.api_provider() {
    let grant = cfg.external_credential_grant(provider, source, &path)?;
}
Defensive patterns

Strategy: validation

Validate before calling

if provider != config.api_provider() {
    eprintln!("skipping external credential import for {provider:?}: not the active provider");
    return;
}

Prevention

When it happens

Trigger: Calling the external-credential grant method (`Result<ExternalCredentialReadGrant>` helper at config.rs:6914) with `provider` whose value differs from `self.api_provider()`.

Common situations: Running an auth-import/onboarding flow while a different provider is selected in config; a session where the user switched `api_provider` after starting the import; scripts that import credentials for several providers in one run without switching the active provider between them.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/3755dd6fa4d70179. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/config.rs:6914

            })
    }

    /// Mint a read capability for the exact external credential path selected
    /// when consent was granted.
    ///
    /// Path resolution itself is side-effect free. The returned capability is
    /// required by every external credential adapter before it may stat or
    /// read the selected file. `suggested_path` is used only in disabled-mode
    /// guidance; an existing grant remains pinned to its persisted path even
    /// if ambient CLI-home environment variables change later.
    pub(crate) fn external_credential_read_grant(
        &self,
        provider: ApiProvider,
        source: codewhale_config::ExternalCredentialSource,
        suggested_path: &Path,
    ) -> Result<codewhale_config::ExternalCredentialReadGrant> {
        if provider != self.api_provider() {
            anyhow::bail!(
                "external credential access for {} is dormant until that provider is explicitly selected",
                provider.display_name()
            );
        }
        let kind = provider
            .metadata()
            .map(codewhale_config::provider::Provider::kind)
            .context("external credentials are unsupported for this provider")?;
        let consent = self
            .provider_config_for(provider)
            .and_then(|entry| entry.external_credentials.as_ref())
            .with_context(|| {
                format!(
                    "External credentials owned by {} are disabled for {}. To allow read-only access to this exact file, run:\n  codewhale auth external-consent --provider {} --mode read-only --path {}",
                    source.as_str(),
                    provider.display_name(),
                    kind.as_str(),
                    codewhale_config::quote_os_path(suggested_path)

View on GitHub (pinned to 73e0f67d83)