wavetermdev/waveterm · error

chatOpts.ClientId is required

Error message

chatOpts.ClientId is required

What it means

buildOpenAIHTTPRequest requires chatOpts.ClientId to be set because the client id ties the streaming response back to the requesting client/session (used for routing SSE output). 'chatOpts.ClientId is required' is thrown when it is empty — a caller-side wiring problem, not a user configuration issue.

Source

Thrown at pkg/aiusechat/openai/openai-convertmessage.go:206

	}
}

// buildOpenAIHTTPRequest creates a complete HTTP request for the OpenAI API
func buildOpenAIHTTPRequest(ctx context.Context, inputs []any, chatOpts uctypes.WaveChatOpts, cont *uctypes.WaveContinueResponse) (*http.Request, error) {
	opts := chatOpts.Config

	// If continuing from premium rate limit, downgrade to default model and medium thinking
	// (medium is more widely supported than low across different models)
	if cont != nil && cont.ContinueFromKind == uctypes.StopKindPremiumRateLimit {
		opts.Model = uctypes.DefaultOpenAIModel
		opts.ThinkingLevel = uctypes.ThinkingLevelMedium
	}

	if opts.Model == "" {
		return nil, errors.New("ai:model is required")
	}
	if chatOpts.ClientId == "" {
		return nil, errors.New("chatOpts.ClientId is required")
	}

	// Set defaults
	endpoint := opts.Endpoint
	if endpoint == "" {
		return nil, errors.New("ai:endpoint is required")
	}

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

	// injected data
	if chatOpts.TabState != "" {
		appendToLastUserMessage(inputs, chatOpts.TabState)
	}
	if chatOpts.PlatformInfo != "" {

View on GitHub (pinned to a4447c1563)

Solutions

  1. Set chatOpts.ClientId to the requesting block/controller id before calling RunOpenAIChatStep
  2. Trace where WaveChatOpts is constructed and ensure ClientId is populated from the active client context
  3. In tests or headless usage, supply a synthetic but non-empty ClientId
  4. Add an early assertion/logging where WaveChatOpts is built to catch empty ClientId during development

Example fix

// before
chatOpts := uctypes.WaveChatOpts{Config: cfg} // ClientId empty
// after
chatOpts := uctypes.WaveChatOpts{Config: cfg, ClientId: blockId}
if chatOpts.ClientId == "" {
    return fmt.Errorf("cannot start chat step without ClientId")
}
Defensive patterns

Strategy: validation

Validate before calling

if chatOpts.ClientId == "" {
    return fmt.Errorf("cannot run OpenAI chat step: ClientId missing")
}

Try / catch

if err != nil && err.Error() == "chatOpts.ClientId is required" {
    return fmt.Errorf("internal error: chat options built without a ClientId; check WaveChatOpts construction")
}

Prevention

When it happens

Trigger: RunOpenAIChatStep is called with chatOpts.ClientId == "": the caller that constructs WaveChatOpts never populated ClientId, the block/controller id was not available at construction time, or opts were copied from a template struct with an empty ClientId.

Common situations: Programmatic/backend use of the AI layer outside the normal block UI flow; tests calling RunOpenAIChatStep with a minimal WaveChatOpts; refactors that changed how client/block ids are generated leaving the field unset.

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/cd69736903d513a9. Report an issue: GitHub.