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

For ApiProvider::Anthropic and Openmodel, the missing-key branch delegates to missing_provider_api_key_message() (crates/tui/src/config.rs:11627), which formats '{display_name} API key not found. Get a key: {url}. Run codewhale auth set --provider {id}, set {env_vars}, or add [{table}] api_key in ~/.codewhale/config.toml.' Every placeholder is provider-derived, so the guidance always names the right command, env vars, and TOML table.

Source

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

                            .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 8880682c63)

Solutions

  1. Run codewhale auth set --provider <provider>.
  2. Or export the provider's env var(s) exactly as named in the message.
  3. Or add api_key under the provider's [providers.<table>] in ~/.codewhale/config.toml.
  4. Get a key from the credential URL included in the message.

Example fix

# before
provider = "anthropic"
# no credentials

# after (terminal)
# codewhale auth set --provider anthropic
# or: export ANTHROPIC_API_KEY=sk-ant-...
Defensive patterns

Strategy: validation

Validate before calling

fn provider_key_present(cfg: &Config, provider: ApiProvider) -> bool {
    provider.env_vars().iter().any(|v| env_nonempty(v)) // e.g. ANTHROPIC_API_KEY
        || cfg.provider_config_for(provider)
            .and_then(|pc| pc.api_key)
            .is_some_and(|k| !k.trim().is_empty())
        || secret_store_has(provider)
}

anyhow::ensure!(provider_key_present(&config, ApiProvider::Anthropic), "auth required");

Type guard

fn provider_credentials_configed(cfg: &Config, provider: ApiProvider) -> bool {
    provider_key_present(cfg, provider)
}

Try / catch

match config.deepseek_api_key() {
    Err(e) if e.to_string().ends_with("API key not found.") || e.to_string().contains("Run 'codewhale auth set --provider") => {
        run_auth_set(provider)?; // interactive: codewhale auth set --provider <id>
        config.deepseek_api_key()
    }
    other => other,
}

Prevention

When it happens

Trigger: provider = anthropic (or openmodel) with no secret-store entry, no provider env var, and no api_key in the provider's config table.

Common situations: Fresh setups; ANTHROPIC_API_KEY unset in non-interactive shells (zshrc vs zshenv); keys wiped by `auth logout` / --logout (#343).

Related errors


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