wavetermdev/waveterm · error
message %d: expected *anthropicChatMessage, got %T
Error message
message %d: expected *anthropicChatMessage, got %T
What it means
ConvertAIChatToUIChat type-asserts each entry of aiChat.NativeMessages to *anthropicChatMessage. A native message of any other concrete type cannot be converted to the Anthropic UI representation, so the loop fails fast with the index and dynamic type of the offending message.
Source
Thrown at pkg/aiusechat/anthropic/anthropic-convertmessage.go:825
return &anthropicChatMessage{
MessageId: uuid.New().String(),
Role: "user",
Content: contentBlocks,
}, nil
}
// ConvertAIChatToUIChat converts an AIChat to a UIChat for Anthropic
func ConvertAIChatToUIChat(aiChat uctypes.AIChat) (*uctypes.UIChat, error) {
if aiChat.APIType != uctypes.APIType_AnthropicMessages {
return nil, fmt.Errorf("APIType must be '%s', got '%s'", uctypes.APIType_AnthropicMessages, aiChat.APIType)
}
uiMessages := make([]uctypes.UIMessage, 0, len(aiChat.NativeMessages))
for i, nativeMsg := range aiChat.NativeMessages {
anthropicMsg, ok := nativeMsg.(*anthropicChatMessage)
if !ok {
return nil, fmt.Errorf("message %d: expected *anthropicChatMessage, got %T", i, nativeMsg)
}
uiMsg := anthropicMsg.ConvertToUIMessage()
if uiMsg != nil {
uiMessages = append(uiMessages, *uiMsg)
}
}
return &uctypes.UIChat{
ChatId: aiChat.ChatId,
APIType: aiChat.APIType,
Model: aiChat.Model,
APIVersion: aiChat.APIVersion,
Messages: uiMessages,
}, nil
}
func GetFunctionCallInputByToolCallId(aiChat uctypes.AIChat, toolCallId string) *uctypes.AIFunctionCallInput {View on GitHub (pinned to a4447c1563)
Solutions
- Only include *anthropicChatMessage values in NativeMessages for Anthropic chats
- Rebuild the chat messages via the Anthropic converter so they get the right concrete type
- Filter or convert foreign messages before calling ConvertAIChatToUIChat
Example fix
// before aiChat.NativeMessages = append(aiChat.NativeMessages, someOpenAIMessage) // after anthMsg, err := anthropic.ConvertAIMessageToAnthropicChatMessage(aiMsg) aiChat.NativeMessages = append(aiChat.NativeMessages, anthMsg)
Defensive patterns
Strategy: type-guard
Validate before calling
for i, m := range aiChat.NativeMessages {
if _, ok := m.(*anthropicChatMessage); !ok {
return fmt.Errorf("native message %d is not an anthropic message", i)
}
} Type guard
func asAnthropicMessage(m uctypes.NativeMessage) (*anthropicChatMessage, bool) {
msg, ok := m.(*anthropicChatMessage)
return msg, ok
} Try / catch
uiChat, err := anthropic.ConvertAIChatToUIChat(aiChat)
if err != nil {
var idx int; var typ string
if _, scan := fmt.Sscanf(err.Error(), "message %d: expected *anthropicChatMessage, got %s", &idx, &typ); scan == nil {
return fmt.Errorf("chat contains foreign message at index %d (%s)", idx, typ)
}
return err
} Prevention
- Only append messages produced by the Anthropic converter to NativeMessages
- Avoid hand-rolled structs in NativeMessages slices
- Add tests asserting every NativeMessage type-asserts to *anthropicChatMessage
When it happens
Trigger: ConvertAIChatToUIChat called on an AIChat whose NativeMessages slice contains a message not created by this package (e.g. *openaiChatMessage, a generic struct, or nil of a different type).
Common situations: Appending messages from another provider into a shared NativeMessages slice; custom message wrappers stored in the chat; cache deserialization yielding the wrong concrete type.
Related errors
- convertFileUIMessagePart expects 'file' type, got '%s'
- unsupported URL protocol in file part: %s
- failed to decode base64 data: %w
- dropping text/plain file with URL (must be fetched and conve
- dropping file with unsupported media type '%s' (must be uplo
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/f48a27869fd1c1f7.
Report an issue: GitHub.