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
- Set chatOpts.ClientId to the requesting block/controller id before calling RunOpenAIChatStep
- Trace where WaveChatOpts is constructed and ensure ClientId is populated from the active client context
- In tests or headless usage, supply a synthetic but non-empty ClientId
- 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
- Populate ClientId from the active block/controller context whenever WaveChatOpts is built
- Never copy WaveChatOpts from a zero-value template without re-setting identity fields
- Assert ClientId is non-empty where chat options are constructed in tests
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
- sse handler is nil
- convertFileAIMessagePart expects 'file' type, got '%s'
- file part missing mimetype
- invalid AIMessage: %w
- part %d: text type requires non-empty text field
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/cd69736903d513a9.
Report an issue: GitHub.