alibaba/open-code-review · error

provider %q: %w

Error message

provider %q: %w

What it means

Wrapper error ("provider %q: %w") from tryProviderConfig when ValidateProtocol rejects the protocol that a preset provider declares internally. This comes from the preset's built-in Protocol after normalization, so hitting it usually means the installed preset table and the binary's validation rules disagree (version skew), not a user typo.

Source

Thrown at internal/llm/resolver.go:433

		}
	case apiKeyCmd == "" && isPreset && preset.EnvVar != "":
		// Env var is the last resort: only when neither api_key nor api_key_cmd
		// is set, and only for preset providers (custom ones have no fallback).
		// Same whitespace rule as the static key above, so `export
		// ANTHROPIC_API_KEY="  "` reports "no api_key configured" instead of
		// sending `Authorization: Bearer  ` and getting an opaque 401.
		if v := os.Getenv(preset.EnvVar); strings.TrimSpace(v) != "" {
			apiKey = v
		}
	}
	var url, protocol, authHeader, model string
	var extraBody map[string]any

	if isPreset {
		url = preset.BaseURL
		protocol = NormalizeProtocol(preset.Protocol)
		if err := ValidateProtocol(protocol); err != nil {
			return ResolvedEndpoint{}, false, fmt.Errorf("provider %q: %w", cfg.Provider, err)
		}
		authHeader = preset.AuthHeader
		if entry.URL != "" {
			url = entry.URL
		}
		if entry.Protocol != "" {
			normalized := NormalizeProtocol(entry.Protocol)
			if err := ValidateProtocol(normalized); err != nil {
				return ResolvedEndpoint{}, false, fmt.Errorf("provider %q: %w", cfg.Provider, err)
			}
			protocol = normalized
		}
	} else {
		// Custom provider: protocol is always required; model can come from
		// cfg.Model. url is required for every protocol that names an HTTP
		// endpoint, which is all of them except bedrock — there the region
		// decides the host, so demanding a url would mean storing a value the
		// client never reads.

View on GitHub (pinned to 5cf97d0d15)

Solutions

  1. Rebuild/reinstall ocr so the preset registry and validator come from the same version
  2. Override the protocol in the provider entry ("protocol": "anthropic" or "openai") to bypass the preset's default
  3. Report/fix the preset definition so its Protocol matches a value accepted by ValidateProtocol

Example fix

// before — providers.json preset: {"name":"acme","protocol":"acme-chat"}

// after — override in config.json
{
  "provider": "acme",
  "providers": { "acme": { "protocol": "openai", "url": "https://api.acme.dev/v1" } }
}
Defensive patterns

Strategy: fallback

Try / catch

if err := resolve(); err != nil {
    if strings.Contains(err.Error(), "provider \"my-provider\": ") && strings.Contains(err.Error(), "protocol") {
        log.Println("preset protocol invalid; setting explicit protocol in entry")
        // retry with "protocol": "openai" in the provider entry
    }
    return err
}

Prevention

When it happens

Trigger: Resolving a preset provider (LookupProvider hit); the preset's Protocol field normalizes to a value ValidateProtocol rejects. The user's config only triggers this by referencing the preset provider.

Common situations: Running a binary built against a newer/older preset registry than the validation code expects, or a locally patched/extended preset list with a hand-written protocol string.

Related errors


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