{"record":{"id":"e8a5db12c61b078d","repo":"alibaba/open-code-review","slug":"model-is-required","errorCode":null,"errorMessage":"model is required","messagePattern":"model is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/opencodereview/provider_cmd.go","lineNumber":163,"sourceCode":"\tfmt.Printf(\"Model: %s\\n\", result.model)\n\n\tfmt.Println(\"\\nTesting connection...\")\n\tif err := runLLMTest(); err != nil {\n\t\tfmt.Fprintf(os.Stderr, \"Connection test failed: %v\\n\", err)\n\t\tfmt.Fprintln(os.Stderr, \"Configuration has been saved. Fix the issue and run 'ocr llm test' to re-verify.\")\n\t\treturn nil\n\t}\n\n\treturn nil\n}\n\nfunc applyCustomProviderConfig(configPath string, cfg *Config, result providerTUIResult) error {\n\tif result.provider == \"\" {\n\t\treturn fmt.Errorf(\"provider name is required\")\n\t}\n\tmodel := result.resolvedModel()\n\tif model == \"\" {\n\t\treturn fmt.Errorf(\"model is required\")\n\t}\n\n\tif cfg.CustomProviders == nil {\n\t\tcfg.CustomProviders = make(map[string]ProviderEntry)\n\t}\n\n\tentry := cfg.CustomProviders[result.provider]\n\tentry.Model = model\n\tif len(result.models) > 0 {\n\t\tentry.Models = append([]string(nil), result.models...)\n\t}\n\tentry.Models = ensureModelInList(entry.Models, model)\n\tif result.url != \"\" {\n\t\tentry.URL = result.url\n\t}\n\tif result.protocol != \"\" {\n\t\tentry.Protocol = result.protocol\n\t}","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/alibaba/open-code-review/blob/5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f/cmd/opencodereview/provider_cmd.go#L145-L181","documentation":"After validating the provider name, applyCustomProviderConfig resolves the model via result.resolvedModel() and refuses to persist a custom provider entry with no model. Custom providers store models in the entry, so an empty model would leave the provider unusable for review requests.","triggerScenarios":"The wizard result has a provider but resolvedModel() returns \"\" — neither the picked model nor the typed model was set; exercised by TestApplyCustomProviderConfig_MissingModel.","commonSituations":"User selects a provider in the wizard but skips/empties the model selection; a custom entry defined only by URL without any model list; a TUI change stops propagating the chosen model into resolvedModel.","solutions":["Pick or type a model in the provider wizard before confirming","Verify resolvedModel() is populated (session model pick or typed model) before saving","Pre-seed the custom provider entry's Models list so a sensible default can resolve"],"exampleFix":"// before\nresult := providerTUIResult{provider: \"my-llm\"} // model empty\n// after\nresult := providerTUIResult{provider: \"my-llm\", model: \"gpt-4o\"}\nerr := applyCustomProviderConfig(path, cfg, result)","handlingStrategy":"validation","validationCode":"if result.provider == \"\" || result.resolvedModel() == \"\" {\n    return errors.New(\"provider and model must both be selected\")\n}\napplyCustomProviderConfig(configPath, cfg, result)","typeGuard":"func isCompleteCustomSelection(r providerTUIResult) bool {\n    return r.provider != \"\" && r.resolvedModel() != \"\"\n}","tryCatchPattern":null,"preventionTips":["Require the model step in the wizard before enabling Confirm","Seed custom entries with a default model so resolvedModel() can resolve","Unit test the empty-model path (as TestApplyCustomProviderConfig_MissingModel does)"],"tags":["config","cli","validation","provider","model"],"backgroundTag":"missing-required-argument","analyzedSha":"5cf97d0d15cbd41b602513c4be3bfec3cee5bf7f","analyzedAt":"2026-09-02T02:08:09.116Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}