wavetermdev/waveterm · error

ai:model is required

Error message

ai:model is required

What it means

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.

Source

Thrown at pkg/aiusechat/gemini/gemini-backend.go:62

// appendPartToLastUserMessage appends a text part to the last user message in the contents slice
func appendPartToLastUserMessage(contents []GeminiContent, text string) {
	for i := len(contents) - 1; i >= 0; i-- {
		if contents[i].Role == "user" {
			contents[i].Parts = append(contents[i].Parts, GeminiMessagePart{
				Text: text,
			})
			break
		}
	}
}

// buildGeminiHTTPRequest creates an HTTP request for the Gemini API
func buildGeminiHTTPRequest(ctx context.Context, contents []GeminiContent, chatOpts uctypes.WaveChatOpts) (*http.Request, error) {
	opts := chatOpts.Config

	if opts.Model == "" {
		return nil, errors.New("ai:model is required")
	}
	if opts.APIToken == "" {
		return nil, errors.New("ai:apitoken is required")
	}
	if opts.Endpoint == "" {
		return nil, errors.New("ai:endpoint is required")
	}

	maxTokens := opts.MaxTokens
	if maxTokens <= 0 {
		maxTokens = GeminiDefaultMaxTokens
	}

	// Build request body
	reqBody := &GeminiRequest{
		Contents: contents,
		GenerationConfig: &GeminiGenerationConfig{
			MaxOutputTokens: int32(maxTokens),

View on GitHub (pinned to a4447c1563)

Solutions

  1. 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
  2. If using per-provider config, ensure the model is set under the Gemini provider block, not another backend's
  3. Reload/restart the app after editing config so the new model value is picked up
  4. Add pre-flight validation in the calling code to surface a friendlier message when opts.Model is empty

Example fix

// before
chatOpts.Config.Model = ""
RunGeminiChatStep(ctx, sseHandler, chatOpts, cont)
// after
if chatOpts.Config.Model == "" {
    chatOpts.Config.Model = "gemini-2.0-flash"
}
RunGeminiChatStep(ctx, sseHandler, chatOpts, cont)
Defensive patterns

Strategy: validation

Validate before calling

if err := validateGeminiConfig(chatOpts.Config); err != nil {
    return err
}

Try / catch

if _, _, _, err := RunGeminiChatStep(ctx, handler, chatOpts, cont); err != nil {
    if err.Error() == "ai:model is required" {
        // surface config UI or apply default model
        chatOpts.Config.Model = "gemini-2.0-flash"
        return retry()
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/a77b7c7635fff6c0. Report an issue: GitHub.