alibaba/open-code-review · error
provider %q has no api_key or api_key_cmd configured and no
Error message
provider %q has no api_key or api_key_cmd configured and no environment variable fallback found
What it means
Endpoint resolution requires a credential: a static `api_key`, an `api_key_cmd` command that produces one, or a preset provider's environment-variable fallback (e.g. ANTHROPIC_API_KEY). The only exception is ambient-auth providers (e.g. bedrock), where requests are SigV4-signed from the environment's own AWS credential chain. This error fires before api_key_cmd is executed, so it means the config is empty of all credential sources for a non-ambient provider.
Source
Thrown at internal/llm/resolver.go:482
}
// Ambient auth follows the protocol actually in force, which is why this is
// resolved after the override above rather than read off the preset. A preset
// declares ambient auth (AmbientAuth), but an entry may override the preset's
// protocol: a bedrock preset switched to "openai" speaks a protocol with no
// SigV4 signing and needs a token like anything else. Conversely an entry
// that selects the bedrock protocol explicitly signs its requests whatever
// the preset says.
ambientAuth := protocol == ProtocolAnthropicBedrock ||
(isPreset && preset.AmbientAuth && entry.Protocol == "")
// No credential at all is an error, and it is reported before api_key_cmd
// runs: only the command's *execution* is deferred, not the emptiness check.
// An ambient-auth provider is the exception — it has no key to configure,
// since credentials come from the environment's own chain and the request is
// signed rather than bearing a token.
if apiKey == "" && apiKeyCmd == "" && !ambientAuth {
return ResolvedEndpoint{}, false, fmt.Errorf("provider %q has no api_key or api_key_cmd configured and no environment variable fallback found", cfg.Provider)
}
if cfg.Model != "" {
model = cfg.Model
}
if entry.Model != "" {
model = entry.Model
}
// Build available model list for validation.
var availableModels []string
if isPreset {
availableModels = append(availableModels, preset.Models...)
}
availableModels = append(availableModels, entry.Models...)
// A preset's Models list doubles as an allowlist for --model. For an
// ambient-auth provider it cannot: Bedrock identifiers are scoped to anView on GitHub (pinned to 5cf97d0d15)
Solutions
- Set api_key in the provider entry in the ocr config file
- Or set api_key_cmd to a command that prints the key (e.g. a secrets-manager CLI)
- For preset providers, export the expected env var (e.g. export ANTHROPIC_API_KEY=sk-...) in the shell/service environment
- If using AWS Bedrock, set protocol to anthropic-bedrock (or use a bedrock preset without a protocol override) so ambient AWS auth applies
Example fix
// before [providers.deepseek] protocol = "openai" url = "https://api.deepseek.com" // after [providers.deepseek] protocol = "openai" url = "https://api.deepseek.com" api_key_cmd = "op read 'op://Vault/deepseek/key'"
Defensive patterns
Strategy: validation
Validate before calling
// Go: pre-flight credential check before invoking ocr
func hasCredential(apiKey, apiKeyCmd, envVar string) error {
if strings.TrimSpace(apiKey) != "" || strings.TrimSpace(apiKeyCmd) != "" {
return nil
}
if envVar != "" && strings.TrimSpace(os.Getenv(envVar)) != "" {
return nil
}
return fmt.Errorf("no credential: set api_key, api_key_cmd, or %s", envVar)
} Type guard
func credentialConfigured(apiKey, apiKeyCmd string, envVars ...string) bool {
if strings.TrimSpace(apiKey) != "" || strings.TrimSpace(apiKeyCmd) != "" {
return true
}
for _, e := range envVars {
if strings.TrimSpace(os.Getenv(e)) != "" {
return true
}
}
return false
} Try / catch
ep, ok, err := resolver.TryProviderConfig(cfg, "")
if err != nil && strings.Contains(err.Error(), "no api_key or api_key_cmd") {
fmt.Fprintln(os.Stderr, "credential missing; run 'ocr config' or export the provider's API key env var")
os.Exit(2)
} Prevention
- Export the preset's env var (ANTHROPIC_API_KEY, etc.) in shell profiles and CI secrets
- Prefer api_key_cmd over a literal api_key so secrets never sit in config files
- Remember custom providers get no env fallback — always set api_key or api_key_cmd for them
- Treat whitespace-only key values as missing; re-enter the key if in doubt
When it happens
Trigger: Resolving a provider entry where: api_key is empty/whitespace, api_key_cmd is empty/whitespace, no preset env var is set in the environment (custom providers get no env fallback at all), and the effective protocol is not bedrock/ambient-auth.
Common situations: Fresh checkout where the API key env var was never exported; running under CI/systemd where the interactive shell env is absent; using a custom provider (no env fallback exists by design) without a key; whitespace-only api_key values which are deliberately treated as unset.
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
- custom provider %q requires a url field for protocol %q
- load config: %w
- unset supports provider, max_tokens, effort, custom_provider
- MCP server %q not found
- custom provider %q not found
AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02).
Data as JSON: /api/errors/d14e3c9acc451d9e.
Report an issue: GitHub.