{"record":{"id":"be2f871b212dae74","repo":"Hmbown/CodeWhale","slug":"has-no-supported-external-credential-owner","errorCode":null,"errorMessage":"{} has no supported external credential owner","messagePattern":"(.+?) has no supported external credential owner","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/config.rs","lineNumber":12844,"sourceCode":"/// persisted consent record.\npub(crate) fn persist_external_credential_consent_for_at(\n    config_path: Option<&Path>,\n    live_config: &mut Config,\n    provider: ApiProvider,\n    consent_provider: codewhale_config::ProviderKind,\n    source: codewhale_config::ExternalCredentialSource,\n    path: &Path,\n) -> Result<PathBuf> {\n    let expected = match provider {\n        ApiProvider::OpenaiCodex => (\n            codewhale_config::ProviderKind::OpenaiCodex,\n            codewhale_config::ExternalCredentialSource::CodexCli,\n        ),\n        ApiProvider::Xai => (\n            codewhale_config::ProviderKind::Xai,\n            codewhale_config::ExternalCredentialSource::GrokCli,\n        ),\n        _ => anyhow::bail!(\n            \"{} has no supported external credential owner\",\n            provider.as_str()\n        ),\n    };\n    anyhow::ensure!(\n        (consent_provider, source) == expected,\n        \"external credential owner does not match provider {}\",\n        provider.as_str()\n    );\n    let path = codewhale_config::resolve_external_credential_path(path)?;\n    let path_value = path.to_str().context(\n        \"external credential path cannot be persisted losslessly because it is not valid UTF-8\",\n    )?;\n    validate_external_credential_before_consent(consent_provider, source, &path).with_context(\n        || {\n            format!(\n                \"no usable {} credential was found, so read-only consent was not saved\",\n                source.owner_label()","sourceCodeStart":12826,"sourceCodeEnd":12862,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/config.rs#L12826-L12862","documentation":"When reconciling an external-consent grant, the provider-to-(kind, source) mapping only covers providers with a supported external credential owner (Codex CLI, Grok CLI, etc.). Any other provider hits the `_` catch-all arm, which bails stating that the provider has no supported external credential owner.","triggerScenarios":"Calling the external-consent/credential-owner resolution with an `ApiProvider` that has no match arm (e.g. a native API-key provider like Anthropic, DeepSeek, or a custom provider) while expecting an external CLI source.","commonSituations":"Running `codewhale auth external-consent --provider <name>` for a provider that does not support CLI-based consent; generic automation iterating all providers and calling the consent routine on each.","solutions":["Only grant external consent for providers with an external CLI owner (e.g. openai-codex via Codex CLI, xai via Grok CLI)","For other providers, save an API key directly instead of using external-consent"],"exampleFix":"// before\ncodewhale auth external-consent --provider anthropic --mode read-only\n// after\ncodewhale auth save --provider anthropic --api-key <key>","handlingStrategy":"validation","validationCode":"let supported = matches!(provider, ApiProvider::OpenaiCodex | ApiProvider::Xai);\nif !supported { eprintln!(\"{} has no external credential owner\", provider.as_str()); }","typeGuard":"fn has_external_owner(p: ApiProvider) -> bool {\n    matches!(p, ApiProvider::OpenaiCodex | ApiProvider::Xai)\n}","tryCatchPattern":"match consent_result {\n    Err(e) if e.to_string().ends_with(\"no supported external credential owner\") => save_api_key_directly(provider),\n    other => other?,\n}","preventionTips":["Only use external-consent for providers backed by an external CLI","Save API keys directly for native API-key providers","Avoid iterating all providers with a generic consent routine"],"tags":["provider","authentication","unsupported"],"backgroundTag":"unsupported-operation","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}