{"record":{"id":"ff5e0ac592c19531","repo":"alibaba/open-code-review","slug":"url-is-required-for-manual-configuration","errorCode":null,"errorMessage":"URL is required for manual configuration","messagePattern":"URL is required for manual configuration","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/opencodereview/provider_cmd.go","lineNumber":105,"sourceCode":"\nfunc removeModels(existing, toRemove []string) []string {\n\tremoveSet := make(map[string]struct{}, len(toRemove))\n\tfor _, m := range toRemove {\n\t\tremoveSet[m] = struct{}{}\n\t}\n\tresult := make([]string, 0, len(existing))\n\tfor _, m := range existing {\n\t\tif _, found := removeSet[m]; found {\n\t\t\tcontinue\n\t\t}\n\t\tresult = append(result, m)\n\t}\n\treturn result\n}\n\nfunc applyManualConfig(configPath string, cfg *Config, result providerTUIResult) error {\n\tif result.url == \"\" {\n\t\treturn fmt.Errorf(\"URL is required for manual configuration\")\n\t}\n\tif result.model == \"\" {\n\t\treturn fmt.Errorf(\"model is required for manual configuration\")\n\t}\n\n\tcfg.Provider = \"\"\n\tcfg.Model = \"\"\n\tcfg.Llm.URL = result.url\n\tcfg.Llm.Model = result.model\n\tcfg.Llm.AuthToken = result.apiKey\n\tauthHeader, err := llm.NormalizeAuthHeader(result.authHeader)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid auth_header: %w\", err)\n\t}\n\tcfg.Llm.AuthHeader = authHeader\n\t// Write the canonical protocol so resolver picks it up directly. Also\n\t// mirror use_anthropic so configs read correctly on older binaries that\n\t// predate llm.protocol: anthropic -> true, the OpenAI family (including","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/cmd/opencodereview/provider_cmd.go#L87-L123","documentation":"applyManualConfig requires a URL when saving a manually configured provider, and refuses to persist a config without one. This is a validation error from the provider TUI's confirm step: the manual path stores url/model/auth fields directly, so an empty URL would produce a config that endpoint resolution can never use.","triggerScenarios":"Confirming the manual-configuration screen of `ocr config provider` with the URL field left empty; programmatically calling applyManualConfig with a providerTUIResult whose url field is \"\".","commonSituations":"Skipping past the URL field in the TUI assuming a default exists; accidentally clearing the field while editing; test harness constructing providerTUIResult without setting url.","solutions":["Reopen `ocr config provider`, choose manual configuration, and enter the full base URL (including e.g. /v1).","If you intended a known provider, pick it from the provider list instead of the manual path so defaults fill in the URL.","In code/tests, set result.url before calling applyManualConfig."],"exampleFix":"// before\nresult := providerTUIResult{model: \"gpt-4o\"}\n// after\nresult := providerTUIResult{url: \"https://api.openai.com/v1\", model: \"gpt-4o\"}","handlingStrategy":"validation","validationCode":"if result.url == \"\" {\n    return errors.New(\"URL is required for manual configuration\")\n}\nu, err := url.Parse(result.url)\nif err != nil || u.Scheme == \"\" || u.Host == \"\" {\n    return errors.New(\"URL must be absolute, e.g. https://api.example.com/v1\")\n}","typeGuard":null,"tryCatchPattern":"if err := applyManualConfig(path, cfg, result); err != nil {\n    if strings.Contains(err.Error(), \"URL is required\") {\n        // re-prompt for the URL\n    }\n}","preventionTips":["Fill in every required field (URL and model) before confirming the TUI.","Use full absolute URLs including the API path prefix (/v1).","Prefer built-in provider selection, which defaults these fields."],"tags":["validation","config","cli","tui"],"backgroundTag":"missing-required-argument","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}