Hmbown/CodeWhale · error

Custom provider ' ' API key not found: the route binds…

Error message

Custom provider '{route_name}' API key not found: the route binds api_key_env = "{env_name}" but that environment variable is not set. Set {env_name} to your key, or remove api_key_env from [providers.{route_name}] to run the endpoint without credentials.

What it means

Thrown during route resolution for a custom provider whose configuration binds `api_key_env` to an environment variable that is unset (or set to whitespace only). The message names the route, the env var, and both remedies: export the variable, or drop `api_key_env` to run the endpoint without credentials.

Solutions

  1. Set the variable: `export <env_name>=<your-key>` in the shell that launches the app
  2. If the endpoint needs no auth, remove the `api_key_env` line from `[providers.<route_name>]` in your config
  3. Verify the spelling of `api_key_env` matches the exported variable exactly (`echo "${<env_name>}"` to confirm it is non-empty)

Example fix

# before (config)
[providers.myroute]
api_key_env = "MYROUTE_API_KEY"
# after — in the launching shell
export MYROUTE_API_KEY="sk-..."
Defensive patterns

Strategy: validation

Validate before calling

let env_name = "MYROUTE_API_KEY";
if std::env::var(env_name).map_or(true, |v| v.trim().is_empty()) {
    eprintln!("{env_name} is not set; the custom provider route will fail to resolve");
}

Prevention

When it happens

Trigger: Starting a session or switching routes to a custom provider `[providers.<name>]` that declares `api_key_env = "..."` while `std::env::var` on that name fails or returns an empty/whitespace value.

Common situations: Exporting the key in one shell but launching the app from another; missing the variable in a service/tmux environment; a typo in the `api_key_env` name versus the actual exported variable; CI environments where secrets are not injected.

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@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/180ab91c84a75935. Report an issue: GitHub.

Appendix: source

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

        // `[providers.<name>] api_key_env = "..."`. This remains safe for a
        // custom endpoint because the binding belongs to that route; ambient
        // provider variables below do not.
        //
        // For a custom provider, a binding that names an unset (or empty)
        // variable is a broken credential contract, not a keyless route: fail
        // loudly with the route-scoped fix instead of silently degrading to
        // the self-hosted loopback keyless fallback below (#5104). Without
        // this, an `api_key_env` route on a loopback host dispatched
        // unauthenticated while the operator believed credentials were wired,
        // and the composer-side preflight recovery never saw an error.
        if provider == ApiProvider::Custom
            && let Some(env_name) = bound_provider_api_key_env_name(self, provider)
        {
            return match std::env::var(&env_name) {
                Ok(value) if !value.trim().is_empty() => Ok(value),
                _ => {
                    let route_name = self.provider.as_deref().unwrap_or("<name>");
                    Err(anyhow::anyhow!(
                        "Custom provider '{route_name}' API key not found: the route binds \
                         api_key_env = \"{env_name}\" but that environment variable is not set. \
                         Set {env_name} to your key, or remove api_key_env from \
                         [providers.{route_name}] to run the endpoint without credentials."
                    ))
                }
            };
        }
        if let Some(value) = provider_config_env_api_key(self, provider) {
            return Ok(value);
        }

        // 2. The dispatcher resolves this same provider slot before launching
        // the TUI. Standalone `codewhale-tui` launches must see the identical
        // durable credential. Auto-detection is file-backed and prompt-free by
        // default; the OS keyring is queried only when the user explicitly
        // selects the system backend.
        if !self.should_skip_secret_store_for_provider(provider)

View on GitHub (pinned to 73e0f67d83)