{"record":{"id":"f151aa56e62e6d5d","repo":"alibaba/open-code-review","slug":"provider-q-w","errorCode":null,"errorMessage":"provider %q: %w","messagePattern":"provider %q: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/llm/resolver.go","lineNumber":433,"sourceCode":"\t\t}\n\tcase apiKeyCmd == \"\" && isPreset && preset.EnvVar != \"\":\n\t\t// Env var is the last resort: only when neither api_key nor api_key_cmd\n\t\t// is set, and only for preset providers (custom ones have no fallback).\n\t\t// Same whitespace rule as the static key above, so `export\n\t\t// ANTHROPIC_API_KEY=\"  \"` reports \"no api_key configured\" instead of\n\t\t// sending `Authorization: Bearer  ` and getting an opaque 401.\n\t\tif v := os.Getenv(preset.EnvVar); strings.TrimSpace(v) != \"\" {\n\t\t\tapiKey = v\n\t\t}\n\t}\n\tvar url, protocol, authHeader, model string\n\tvar extraBody map[string]any\n\n\tif isPreset {\n\t\turl = preset.BaseURL\n\t\tprotocol = NormalizeProtocol(preset.Protocol)\n\t\tif err := ValidateProtocol(protocol); err != nil {\n\t\t\treturn ResolvedEndpoint{}, false, fmt.Errorf(\"provider %q: %w\", cfg.Provider, err)\n\t\t}\n\t\tauthHeader = preset.AuthHeader\n\t\tif entry.URL != \"\" {\n\t\t\turl = entry.URL\n\t\t}\n\t\tif entry.Protocol != \"\" {\n\t\t\tnormalized := NormalizeProtocol(entry.Protocol)\n\t\t\tif err := ValidateProtocol(normalized); err != nil {\n\t\t\t\treturn ResolvedEndpoint{}, false, fmt.Errorf(\"provider %q: %w\", cfg.Provider, err)\n\t\t\t}\n\t\t\tprotocol = normalized\n\t\t}\n\t} else {\n\t\t// Custom provider: protocol is always required; model can come from\n\t\t// cfg.Model. url is required for every protocol that names an HTTP\n\t\t// endpoint, which is all of them except bedrock — there the region\n\t\t// decides the host, so demanding a url would mean storing a value the\n\t\t// client never reads.","sourceCodeStart":415,"sourceCodeEnd":451,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/internal/llm/resolver.go#L415-L451","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Rebuild/reinstall ocr so the preset registry and validator come from the same version","Override the protocol in the provider entry (\"protocol\": \"anthropic\" or \"openai\") to bypass the preset's default","Report/fix the preset definition so its Protocol matches a value accepted by ValidateProtocol"],"exampleFix":"// before — providers.json preset: {\"name\":\"acme\",\"protocol\":\"acme-chat\"}\n\n// after — override in config.json\n{\n  \"provider\": \"acme\",\n  \"providers\": { \"acme\": { \"protocol\": \"openai\", \"url\": \"https://api.acme.dev/v1\" } }\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := resolve(); err != nil {\n    if strings.Contains(err.Error(), \"provider \\\"my-provider\\\": \") && strings.Contains(err.Error(), \"protocol\") {\n        log.Println(\"preset protocol invalid; setting explicit protocol in entry\")\n        // retry with \"protocol\": \"openai\" in the provider entry\n    }\n    return err\n}","preventionTips":["Keep the ocr binary and its preset data from the same build/version","Set an explicit \"protocol\" in provider entries when you depend on a specific wire format","Report preset/validator mismatches upstream instead of patching preset tables"],"tags":["configuration","provider","protocol","versioning"],"backgroundTag":"invalid-protocol-value","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}