Hmbown/CodeWhale · error · anyhow::Error

API key not found. Run 'codewhale auth set --provider '…

Error message

{} API key not found.{} Run 'codewhale auth set --provider {}', set {}, or add [{}] api_key in ~/.codewhale/config.toml.

What it means

Anthropic and Openmodel routes share the generic missing-key formatter missing_provider_api_key_message (crates/tui/src/config.rs:12020). The message interpolates the provider display name, an optional 'Get a key: URL.' hint from provider metadata, the provider slug for 'codewhale auth set', the env var label, and the config table name. It fires when the whole credential chain for these providers is empty and no earlier arm (custom endpoint, OAuth) matched.

Solutions

  1. Run 'codewhale auth set --provider anthropic' (or the Openmodel slug shown in the error)
  2. Export the env var named by env_vars_label (e.g. ANTHROPIC_API_KEY for the route)
  3. Add api_key under the table named in the error ([providers.anthropic] / [providers.openmodel]) in ~/.codewhale/config.toml

Example fix

# before
[providers.anthropic]
model = "claude-..."

# after
[providers.anthropic]
model = "claude-..."
api_key = "sk-ant-..."
Defensive patterns

Strategy: try-catch

Validate before calling

if matches!(provider, ApiProvider::Anthropic | ApiProvider::Openmodel) {
    let present = std::env::var(provider_env_var(provider))
        .is_ok_and(|v| !v.trim().is_empty())
        || route_table(provider).api_key.is_some()
        || auth_store_has(provider);
    if !present {
        eprintln!("missing {} key; run codewhale auth set --provider {}", provider.display_name(), provider.as_str());
    }
}

Try / catch

match config.deepseek_api_key() {
    Err(e) if e.to_string().contains("API key not found")
        && matches!(provider, ApiProvider::Anthropic | ApiProvider::Openmodel) =>
    {
        // the message already lists auth set / env var / config table; prompt and retry
    }
    other => other?,
}

Prevention

When it happens

Trigger: provider is ApiProvider::Anthropic or ApiProvider::Openmodel, no custom endpoint, and no api_key in config/auth store/env for the route. The dedicated match arm calls missing_provider_api_key_message(provider)? and bails with the formatted string.

Common situations: New machine without ANTHROPIC_API_KEY; the key living only in a CI secret while testing locally; switching from another provider and forgetting the Anthropic credential; logout having cleared stored keys.

Understand the failure class

Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.

Related errors


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

Appendix: source

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

                            .unwrap_or(KIMI_CODE_MEMBERSHIP_PLAN_CONSOLE_URL),
                        provider.env_vars_label(),
                        provider_config_table_name(provider)?
                    );
                }
                anyhow::bail!(
                    "Moonshot/Kimi API key not found. Get a key: {}. Run 'codewhale auth set --provider moonshot', \
                     set {}, or add [{}] api_key. \
                     For a Kimi Code plan key, set [providers.moonshot] base_url = \
                     \"https://api.kimi.com/coding/v1\" and model = \"kimi-for-coding\".",
                    credential_help
                        .credential_url
                        .unwrap_or("https://platform.kimi.ai/console/api-keys"),
                    provider.env_vars_label(),
                    provider_config_table_name(provider)?
                );
            }
            ApiProvider::Anthropic | ApiProvider::Openmodel => {
                anyhow::bail!("{}", missing_provider_api_key_message(provider)?)
            }
            ApiProvider::OpencodeZen => {
                anyhow::bail!("{}", missing_provider_api_key_message(provider)?)
            }
            ApiProvider::OpenaiCodex => anyhow::bail!("{}", crate::oauth::missing_auth_message()),
            ApiProvider::Xai => {
                // Prefer OAuth guidance when auth_mode requests it or Grok CLI
                // tokens already exist; otherwise show both API-key and OAuth.
                if self
                    .provider_config_for(provider)
                    .is_some_and(provider_config_uses_xai_oauth)
                    || crate::xai_oauth::credentials_present(self)
                {
                    anyhow::bail!("{}", crate::xai_oauth::missing_auth_message());
                }
                anyhow::bail!(
                    "xAI API key not found. Get a key: https://console.x.ai/\n\
                     Run 'codewhale auth set --provider xai', set XAI_API_KEY, or add \

View on GitHub (pinned to 0c42157ee5)