wavetermdev/waveterm · error

expected StoredChatMessage, got %T

Error message

expected StoredChatMessage, got %T

What it means

RunChatStep converts the stored chat's NativeMessages, asserting each is a *StoredChatMessage; any other concrete type fails this assertion with the actual type reported. The openaichat backend only understands its own stored message wrapper.

Solutions

  1. Ensure only messages created by the openaichat backend are added to this chat's NativeMessages
  2. Convert or re-create foreign messages as StoredChatMessage before running the step
  3. Check the chat-loading code isn't deserializing into the wrong message type

Example fix

// before
chat.NativeMessages = append(chat.NativeMessages, openaiMsg) // wrong type
// after
chat.NativeMessages = append(chat.NativeMessages, &StoredChatMessage{Message: toStored(openaiMsg)})
Defensive patterns

Strategy: type-guard

Validate before calling

for i, m := range chat.NativeMessages {
    if _, ok := m.(*StoredChatMessage); !ok {
        return fmt.Errorf("native message %d is %T, not StoredChatMessage", i, m)
    }
}

Type guard

func isStoredChatMessage(m any) bool { _, ok := m.(*StoredChatMessage); return ok }

Prevention

When it happens

Trigger: chat.NativeMessages contains native messages produced by another backend (e.g. *OpenAIChatMessage from the openai responses backend) instead of *StoredChatMessage.

Common situations: Persisting/loading chats across backends; mixing backends in one chat history; upgrading the library where message representations changed.

Related errors


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

Appendix: source

Thrown at pkg/aiusechat/openaichat/openaichat-backend.go:54

	chat := chatstore.DefaultChatStore.Get(chatOpts.ChatId)
	if chat == nil {
		return nil, nil, nil, fmt.Errorf("chat not found: %s", chatOpts.ChatId)
	}

	if chatOpts.Config.TimeoutMs > 0 {
		var cancel context.CancelFunc
		ctx, cancel = context.WithTimeout(ctx, time.Duration(chatOpts.Config.TimeoutMs)*time.Millisecond)
		defer cancel()
	}

	// Convert stored messages to chat completions format
	var messages []ChatRequestMessage

	// Convert native messages
	for _, genMsg := range chat.NativeMessages {
		chatMsg, ok := genMsg.(*StoredChatMessage)
		if !ok {
			return nil, nil, nil, fmt.Errorf("expected StoredChatMessage, got %T", genMsg)
		}
		messages = append(messages, *chatMsg.Message.clean())
	}

	req, err := buildChatHTTPRequest(ctx, messages, chatOpts)
	if err != nil {
		return nil, nil, nil, err
	}

	client, err := aiutil.MakeHTTPClient(chatOpts.Config.ProxyURL)
	if err != nil {
		return nil, nil, nil, err
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, nil, nil, fmt.Errorf("request failed: %w", err)
	}
	defer resp.Body.Close()

View on GitHub (pinned to a4447c1563)