Hmbown/CodeWhale · error

external credential owner does not match provider

Error message

external credential owner does not match provider {}

What it means

When granting an external credential file access, the code computes an expected (consent_provider, source) pair for the provider being authorized and compares it with the pair attached to the consent record. This ensure! fires when the recorded consent's owner/origin does not match the provider it is being applied to, preventing a credential consent granted for one provider from being reused for another.

Solutions

  1. Regenerate the consent for the correct provider instead of reusing the mismatched record
  2. Remove the stale consent entry from the config and re-run the grant flow for this provider
  3. Verify the provider argument matches the provider the credential file/consent was actually created for

Example fix

// before
apply_external_credential_consent(consent_for(ApiProvider::Xai), ApiProvider::OpenaiCodex)?;
// after
let consent = consent_for(ApiProvider::OpenaiCodex); // consent owner must match target
apply_external_credential_consent(consent, ApiProvider::OpenaiCodex)?;
Defensive patterns

Strategy: try-catch

Validate before calling

// verify consent owner matches target provider before applying
anyhow::ensure!(consent.provider == target_provider, "consent owner mismatch");

Try / catch

match apply_consent(consent, provider) {
    Err(e) if e.to_string().starts_with("external credential owner does not match") => {
        regrant_consent_for(provider);
    }
    other => other?,
}

Prevention

When it happens

Trigger: Applying or persisting an external-credential consent whose (consent_provider, source) tuple differs from the expected pair for the given ApiProvider — e.g. replaying a stored consent under a different provider, or a config file whose consent fields were hand-edited.

Common situations: Migrating or copying consent entries between providers; hand-editing the config and moving a consent block under the wrong provider; a bug writing the consent record with the wrong provider field.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

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

    consent_provider: codewhale_config::ProviderKind,
    source: codewhale_config::ExternalCredentialSource,
    path: &Path,
) -> Result<PathBuf> {
    let expected = match provider {
        ApiProvider::OpenaiCodex => (
            codewhale_config::ProviderKind::OpenaiCodex,
            codewhale_config::ExternalCredentialSource::CodexCli,
        ),
        ApiProvider::Xai => (
            codewhale_config::ProviderKind::Xai,
            codewhale_config::ExternalCredentialSource::GrokCli,
        ),
        _ => anyhow::bail!(
            "{} has no supported external credential owner",
            provider.as_str()
        ),
    };
    anyhow::ensure!(
        (consent_provider, source) == expected,
        "external credential owner does not match provider {}",
        provider.as_str()
    );
    let path = codewhale_config::resolve_external_credential_path(path)?;
    let path_value = path.to_str().context(
        "external credential path cannot be persisted losslessly because it is not valid UTF-8",
    )?;
    validate_external_credential_before_consent(consent_provider, source, &path).with_context(
        || {
            format!(
                "no usable {} credential was found, so read-only consent was not saved",
                source.owner_label()
            )
        },
    )?;
    let config_path = match config_path {
        Some(path) => path.to_path_buf(),

View on GitHub (pinned to 73e0f67d83)