wavetermdev/waveterm · error

chatOpts.ClientId is required

Error message

chatOpts.ClientId is required

What it means

buildAnthropicHTTPRequest requires chatOpts.ClientId, which identifies the calling client/block for the request. An empty ClientId breaks request construction and possibly downstream authorization/bookkeeping, so the code rejects it before building the HTTP request.

Source

Thrown at pkg/aiusechat/anthropic/anthropic-convertmessage.go:37

	"github.com/google/uuid"
	"github.com/wavetermdev/waveterm/pkg/aiusechat/chatstore"
	"github.com/wavetermdev/waveterm/pkg/aiusechat/uctypes"
	"github.com/wavetermdev/waveterm/pkg/util/logutil"
	"github.com/wavetermdev/waveterm/pkg/util/utilfn"
	"github.com/wavetermdev/waveterm/pkg/wavebase"
)

// these conversions are based off the anthropic spec
// and the aiprompts/aisdk-uimessage-type.md doc (v5)

// buildAnthropicHTTPRequest creates a complete HTTP request for the Anthropic API
func buildAnthropicHTTPRequest(ctx context.Context, msgs []anthropicInputMessage, chatOpts uctypes.WaveChatOpts) (*http.Request, error) {
	opts := chatOpts.Config
	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 = AnthropicDefaultMaxTokens
	}

	// Convert messages to clear FileName fields from Source blocks
	convertedMsgs := make([]anthropicInputMessage, len(msgs))
	for i, msg := range msgs {
		convertedMsgs[i] = convertMessageForAPI(msg)
	}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Populate chatOpts.ClientId from the block/context id before invoking the chat step.
  2. Use the standard entry point that assembles WaveChatOpts from block metadata rather than hand-building opts.
  3. Assert ClientId non-empty in the caller with a descriptive error.

Example fix

// before
opts := uctypes.WaveChatOpts{ChatId: chatId, Config: cfg}

// after
opts := uctypes.WaveChatOpts{ChatId: chatId, ClientId: blockId, Config: cfg}
Defensive patterns

Strategy: validation

Validate before calling

if chatOpts.ClientId == "" {
    return fmt.Errorf("config error: ClientId (block id) required for anthropic chat")
}

Type guard

func hasClientId(o uctypes.WaveChatOpts) bool { return o.ClientId != "" }

Try / catch

if err := validateChatOpts(chatOpts); err != nil {
    return err // fails fast on empty ClientId before the API call
}

Prevention

When it happens

Trigger: RunAnthropicChatStep invoked with WaveChatOpts whose ClientId field is empty — typically when the caller builds opts manually instead of deriving them from the block context.

Common situations: Background/standalone runners calling the AI step without a block context; tests constructing WaveChatOpts literal; a refactor that renamed or stopped populating ClientId upstream.

Understand the failure class

Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.

Related errors


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