wavetermdev/waveterm · error
invalid AIMessage: %w
Error message
invalid AIMessage: %w
What it means
ConvertAIMessageToOpenAIChatMessage first validates the incoming uctypes.AIMessage; if aiMsg.Validate() returns an error the message cannot be safely converted to an OpenAI chat message, so the function aborts and wraps the validation error with this prefix. The wrapped inner error describes the exact structural problem (e.g. missing role or parts).
Source
Thrown at pkg/aiusechat/openai/openai-convertmessage.go:402
formattedText := aiutil.FormatAttachedDirectoryListing(part.FileName, jsonContent)
return &OpenAIMessageContent{
Type: "input_text",
Text: formattedText,
}, nil
default:
return nil, fmt.Errorf("dropping file with unsupported mimetype '%s' (OpenAI supports images, PDFs, text/plain, and directories)", part.MimeType)
}
}
// ConvertAIMessageToOpenAIChatMessage converts an AIMessage to OpenAIChatMessage
// These messages are ALWAYS role "user"
// Handles text parts, images, PDFs, and text/plain files
func ConvertAIMessageToOpenAIChatMessage(aiMsg uctypes.AIMessage) (*OpenAIChatMessage, error) {
if err := aiMsg.Validate(); err != nil {
return nil, fmt.Errorf("invalid AIMessage: %w", err)
}
var contentBlocks []OpenAIMessageContent
imageCount := 0
imageFailCount := 0
for i, part := range aiMsg.Parts {
switch part.Type {
case uctypes.AIMessagePartTypeText:
if part.Text == "" {
return nil, fmt.Errorf("part %d: text type requires non-empty text field", i)
}
contentBlocks = append(contentBlocks, OpenAIMessageContent{
Type: "input_text",
Text: part.Text,
})
case uctypes.AIMessagePartTypeFile:View on GitHub (pinned to a4447c1563)
Solutions
- Log/print the wrapped inner error from Validate() to see which field is invalid
- Fix the AIMessage construction to populate all fields required by Validate() (role, parts, etc.)
- If loading from storage, re-validate after unmarshal and repair or drop invalid messages
- Use the library's constructors/helpers for AIMessage instead of raw struct literals
Example fix
// before
msg := uctypes.AIMessage{}
out, err := ConvertAIMessageToOpenAIChatMessage(msg) // invalid AIMessage: ...
// after
msg := uctypes.AIMessage{Role: uctypes.RoleUser, Parts: []uctypes.AIMessagePart{{Type: uctypes.AIMessagePartTypeText, Text: "hello"}}}
if err := msg.Validate(); err != nil { return err }
out, err := ConvertAIMessageToOpenAIChatMessage(msg) Defensive patterns
Strategy: validation
Validate before calling
if err := aiMsg.Validate(); err != nil {
return fmt.Errorf("cannot convert message: %w", err)
} Type guard
func isValidAIMessage(msg uctypes.AIMessage) bool { return msg.Validate() == nil } Prevention
- Always call Validate() on AIMessage before conversion
- Use library constructors rather than raw struct literals
- Validate after deserializing stored chats
When it happens
Trigger: Calling ConvertAIMessageToNativeChatMessage (or ConvertAIMessageToOpenAIChatMessage directly) with an AIMessage whose Validate() fails — typically an AIMessage constructed programmatically with missing/invalid required fields instead of one produced by the chat pipeline.
Common situations: Hand-constructing AIMessage structs in tests or tools and forgetting required fields; deserializing stored chats where fields were dropped; passing a zero-value AIMessage{} after a failed unmarshal.
Related errors
- convertFileAIMessagePart expects 'file' type, got '%s'
- file part missing mimetype
- file part missing url
- file part missing mediaType
- invalid data URL format
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/ca64326ae34b5f85.
Report an issue: GitHub.