alibaba/open-code-review · error

provider %q is set but not configured in %s section

Error message

provider %q is set but not configured in %s section

What it means

tryProviderConfig fails with this error when the top-level "provider" key names a provider that has no matching entry in the config file. Preset providers must appear under "providers", custom providers under "custom_providers"; the error names the correct section for the chosen provider.

Source

Thrown at internal/llm/resolver.go:386

}

// tryProviderConfig resolves an endpoint from the provider-based configuration.
func tryProviderConfig(cfg configFile, modelOverride string) (ResolvedEndpoint, bool, error) {
	preset, isPreset := LookupProvider(cfg.Provider)

	var entry providerEntryConfig
	var ok bool
	if isPreset {
		entry, ok = cfg.Providers[cfg.Provider]
	} else {
		entry, ok = cfg.CustomProviders[cfg.Provider]
	}
	if !ok {
		section := "providers"
		if !isPreset {
			section = "custom_providers"
		}
		return ResolvedEndpoint{}, false, fmt.Errorf("provider %q is set but not configured in %s section", cfg.Provider, section)
	}

	// Pick the credential source here, but run api_key_cmd only just before
	// returning (see below): a config typo must not trigger a secret-manager
	// prompt before the cheap validation below has had a chance to fail.
	// A whitespace-only api_key is a typo, not a credential: treat it as unset so
	// it cannot silently shadow a working api_key_cmd (which otherwise resolves to
	// a 401 with the command never running). A key with real content is used
	// verbatim -- unlike command stdout, which has a mechanical trailing newline
	// to strip, a static value has no artifact that trimming must undo.
	apiKey := entry.APIKey
	if strings.TrimSpace(apiKey) == "" {
		apiKey = ""
	}
	// Same rule for the command: `sh -c "   "` exits 0 with no output, so a
	// whitespace-only api_key_cmd would suppress the env fallback and then fail
	// with "produced empty output". Treating it as unset keeps the typo from
	// being more disruptive than the equivalent typo in api_key.

View on GitHub (pinned to 5cf97d0d15)

Solutions

  1. Add a matching entry under the section named in the error ("providers" for presets, "custom_providers" for custom ones) keyed by the exact provider name
  2. Fix the spelling of "provider" so it matches an existing entry key
  3. Remove the "provider" key to fall back to the legacy llm block configuration
  4. If using --provider, pass a name that exists in the config

Example fix

// before
{ "provider": "deepseek" }

// after
{
  "provider": "deepseek",
  "providers": { "deepseek": { "model": "deepseek-chat" } }
}
Defensive patterns

Strategy: validation

Validate before calling

var cfg struct {
    Provider        string            `json:"provider"`
    Providers       map[string]any    `json:"providers"`
    CustomProviders map[string]any    `json:"custom_providers"`
}
json.Unmarshal(data, &cfg)
if cfg.Provider != "" {
    if _, ok := cfg.Providers[cfg.Provider]; !ok {
        if _, ok := cfg.CustomProviders[cfg.Provider]; !ok {
            return fmt.Errorf("provider %q has no entry in providers or custom_providers", cfg.Provider)
        }
    }
}

Prevention

When it happens

Trigger: config.json (or --provider override) sets "provider": "X", but cfg.Providers has no key "X" when X is a known preset, or cfg.CustomProviders has no key "X" when X is not a preset.

Common situations: Typo in the provider name; putting a preset name under custom_providers or a custom name under providers; deleting the entry while leaving "provider" set; passing --provider with a name never configured.

Related errors


AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02). Data as JSON: /api/errors/2a0f411c79e31bee. Report an issue: GitHub.