alibaba/open-code-review · error
custom provider %q requires a protocol field
Error message
custom provider %q requires a protocol field
What it means
A custom provider (one without a preset) must always declare a "protocol" field, because unlike presets there is no built-in default to fall back to. tryProviderConfig raises this error when a custom_providers entry has an empty protocol. Protocol is what decides URL requirements and auth behavior, so it cannot be inferred.
Source
Thrown at internal/llm/resolver.go:453
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.
if entry.Protocol == "" {
return ResolvedEndpoint{}, false, fmt.Errorf("custom provider %q requires a protocol field", cfg.Provider)
}
normalized := NormalizeProtocol(entry.Protocol)
if err := ValidateProtocol(normalized); err != nil {
return ResolvedEndpoint{}, false, fmt.Errorf("custom provider %q: %w", cfg.Provider, err)
}
if normalized != ProtocolAnthropicBedrock && entry.URL == "" {
return ResolvedEndpoint{}, false, fmt.Errorf("custom provider %q requires a url field for protocol %q", cfg.Provider, normalized)
}
url = entry.URL
protocol = normalized
}
// 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 whateverView on GitHub (pinned to 5cf97d0d15)
Solutions
- Add "protocol" to the custom provider entry: "anthropic", "openai", "openai-responses", or "anthropic-bedrock"
- If the endpoint is OpenAI-compatible, use "protocol": "openai"
- If the backend is actually a known vendor, use its preset name under "providers" instead of custom_providers
Example fix
// before
{ "provider": "my-gateway", "custom_providers": { "my-gateway": { "url": "https://gw.internal/v1", "api_key": "sk-..." } } }
// after
{ "provider": "my-gateway", "custom_providers": { "my-gateway": { "url": "https://gw.internal/v1", "api_key": "sk-...", "protocol": "openai" } } } Defensive patterns
Strategy: validation
Validate before calling
var cfg struct {
CustomProviders map[string]struct{ Protocol string `json:"protocol"` } `json:"custom_providers"`
}
json.Unmarshal(data, &cfg)
for name, e := range cfg.CustomProviders {
if e.Protocol == "" {
return fmt.Errorf("custom provider %q is missing required field \"protocol\"", name)
}
} Prevention
- Treat protocol as a mandatory field for every custom_providers entry
- Use "openai" for any OpenAI-compatible gateway
- If the backend matches a preset, configure it under "providers" instead
When it happens
Trigger: config.json has "provider": "X" where X is not a known preset, and cfg.CustomProviders["X"].Protocol is empty or omitted.
Common situations: Adding a new self-hosted/OpenAI-compatible gateway and only filling in url and api_key, assuming the protocol is guessed from the URL; copying a preset entry shape into custom_providers.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02).
Data as JSON: /api/errors/f8c467fa4aaa3897.
Report an issue: GitHub.