Hmbown/CodeWhale · error
DeepSeek stores auth at the root config level
Error message
DeepSeek stores auth at the root config level
What it means
`provider_config_key` maps an `ApiProvider` to its per-provider config key, but DeepSeek (and DeepSeek CN) intentionally have no per-provider slot: their auth is stored at the root config level. The function bails rather than returning a key that would create a parallel storage location.
Solutions
- Store/read DeepSeek auth at the root config level, not a provider slot
- Use the DeepSeek-specific root-level credential path (there is a `clear_deepseek_provider_slot` parameter in the save routine for exactly this)
- For `codewhale auth clear --provider deepseek`, the root-level removal path handles it automatically
Defensive patterns
Strategy: try-catch
Validate before calling
if matches!(provider, ApiProvider::Deepseek | ApiProvider::DeepseekCN) {
eprintln!("use root-level auth config for DeepSeek");
} else { let key = provider_config_key(provider)?; } Type guard
fn has_provider_config_key(p: ApiProvider) -> bool {
!matches!(p, ApiProvider::Deepseek | ApiProvider::DeepseekCN)
} Try / catch
match provider_config_key(provider) {
Err(e) if e.to_string().contains("root config level") => use_root_level_auth(provider),
other => other?,
} Prevention
- Special-case DeepSeek (both variants) in any per-provider config iteration
- Store DeepSeek credentials at the root config level
- Read provider metadata before assuming a per-provider slot exists
When it happens
Trigger: Calling `provider_config_key(ApiProvider::Deepseek)` or `provider_config_key(ApiProvider::DeepseekCN)` — e.g. during credential save/delete flows that assume every provider has its own config slot.
Common situations: Generic code that iterates providers and calls `provider_config_key` for each; user scripts or TUI flows saving/deleting DeepSeek credentials through the per-provider path.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Custom provider ' ' has no auth configured. Add api_key_env…
- DeepSeek Harness credentials line
- Ollama Cloud API key not found. Get a key
- xAI API key not found. Get a key: https://console.x.ai/ Run…
- a CNB access token is not configured in the Codewhale…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/471eb0c2c6e9e93c.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/config.rs:12964
&["providers", key_inside, "external_credentials"],
)?;
Ok(())
})
.with_context(|| {
format!(
"Failed to write config to {}",
codewhale_config::quote_os_path(&config_path)
)
})?;
live_config
.provider_config_for_mut(provider)
.external_credentials = None;
Ok(config_path)
}
pub(crate) fn provider_config_key(provider: ApiProvider) -> Result<&'static str> {
if matches!(provider, ApiProvider::Deepseek | ApiProvider::DeepseekCN) {
anyhow::bail!("DeepSeek stores auth at the root config level");
}
provider
.metadata()
.map(|metadata| metadata.provider_config_key())
.context("provider config key")
}
fn provider_config_table_name(provider: ApiProvider) -> Result<String> {
Ok(format!("providers.{}", provider_config_key(provider)?))
}
fn provider_env_api_key(provider: ApiProvider) -> Option<String> {
if provider == ApiProvider::Huggingface {
return std::env::var("HUGGINGFACE_API_KEY")
.ok()
.filter(|value| !value.trim().is_empty())
.or_else(|| {
std::env::var("HF_TOKEN")View on GitHub (pinned to 73e0f67d83)