{"record":{"id":"a77b7c7635fff6c0","repo":"wavetermdev/waveterm","slug":"ai-model-is-required-a77b7c","errorCode":null,"errorMessage":"ai:model is required","messagePattern":"ai:model is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/aiusechat/gemini/gemini-backend.go","lineNumber":62,"sourceCode":"\n// appendPartToLastUserMessage appends a text part to the last user message in the contents slice\nfunc appendPartToLastUserMessage(contents []GeminiContent, text string) {\n\tfor i := len(contents) - 1; i >= 0; i-- {\n\t\tif contents[i].Role == \"user\" {\n\t\t\tcontents[i].Parts = append(contents[i].Parts, GeminiMessagePart{\n\t\t\t\tText: text,\n\t\t\t})\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// buildGeminiHTTPRequest creates an HTTP request for the Gemini API\nfunc buildGeminiHTTPRequest(ctx context.Context, contents []GeminiContent, chatOpts uctypes.WaveChatOpts) (*http.Request, error) {\n\topts := chatOpts.Config\n\n\tif opts.Model == \"\" {\n\t\treturn nil, errors.New(\"ai:model is required\")\n\t}\n\tif opts.APIToken == \"\" {\n\t\treturn nil, errors.New(\"ai:apitoken is required\")\n\t}\n\tif opts.Endpoint == \"\" {\n\t\treturn nil, errors.New(\"ai:endpoint is required\")\n\t}\n\n\tmaxTokens := opts.MaxTokens\n\tif maxTokens <= 0 {\n\t\tmaxTokens = GeminiDefaultMaxTokens\n\t}\n\n\t// Build request body\n\treqBody := &GeminiRequest{\n\t\tContents: contents,\n\t\tGenerationConfig: &GeminiGenerationConfig{\n\t\t\tMaxOutputTokens: int32(maxTokens),","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/aiusechat/gemini/gemini-backend.go#L44-L80","documentation":"buildGeminiHTTPRequest validates the WaveChatOpts.Config before constructing the Gemini API request. The 'ai:model is required' error is thrown when opts.Model is empty because the Gemini API needs an explicit model name to build the request URL and payload. The library does not apply a default model for Gemini.","triggerScenarios":"RunGeminiChatStep is invoked with chatOpts.Config.Model == \"\" — e.g. the user's settings never specified ai:model, the model was cleared in config, or the Gemini backend was selected without a per-backend model override.","commonSituations":"Fresh install where only the API token was configured; switching from another provider (OpenAI/Anthropic) that has its own default model to Gemini; a config migration or typo'd key (model defined under the wrong backend section) leaving the Gemini model empty.","solutions":["Set the ai:model setting (e.g. in Wave's AI config) to a valid Gemini model such as gemini-2.0-flash or gemini-1.5-pro","If using per-provider config, ensure the model is set under the Gemini provider block, not another backend's","Reload/restart the app after editing config so the new model value is picked up","Add pre-flight validation in the calling code to surface a friendlier message when opts.Model is empty"],"exampleFix":"// before\nchatOpts.Config.Model = \"\"\nRunGeminiChatStep(ctx, sseHandler, chatOpts, cont)\n// after\nif chatOpts.Config.Model == \"\" {\n    chatOpts.Config.Model = \"gemini-2.0-flash\"\n}\nRunGeminiChatStep(ctx, sseHandler, chatOpts, cont)","handlingStrategy":"validation","validationCode":"if err := validateGeminiConfig(chatOpts.Config); err != nil {\n    return err\n}","typeGuard":null,"tryCatchPattern":"if _, _, _, err := RunGeminiChatStep(ctx, handler, chatOpts, cont); err != nil {\n    if err.Error() == \"ai:model is required\" {\n        // surface config UI or apply default model\n        chatOpts.Config.Model = \"gemini-2.0-flash\"\n        return retry()\n    }\n    return err\n}","preventionTips":["Configure ai:model before selecting the Gemini backend","Keep per-provider config sections distinct so a model set for OpenAI is not mistaken for a Gemini model","Validate the full config (model, token, endpoint) at startup and surface gaps to the user"],"tags":["gemini","configuration","missing-model"],"backgroundTag":"missing-config-value","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}