wavetermdev/waveterm · error
part %d: unsupported part type '%s'
Error message
part %d: unsupported part type '%s'
What it means
ConvertAIMessageToAnthropicChatMessage only understands two part types: text and file. Any other AIMessagePartType (e.g. tool-call, thinking, image-as-its-own-type, or unknown/garbage type values) hits the default branch and is rejected with the offending type name and its index.
Source
Thrown at pkg/aiusechat/anthropic/anthropic-convertmessage.go:487
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, anthropicMessageContentBlock{
Type: "text",
Text: part.Text,
})
case uctypes.AIMessagePartTypeFile:
block, err := convertFileAIMessagePart(part)
if err != nil {
return nil, fmt.Errorf("part %d: %w", i, err)
}
contentBlocks = append(contentBlocks, *block)
default:
return nil, fmt.Errorf("part %d: unsupported part type '%s'", i, part.Type)
}
}
return &anthropicChatMessage{
MessageId: aiMsg.MessageId,
Role: "user",
Content: contentBlocks,
}, nil
}
// hasInlineData checks if the part has data available for inline use (either Data field or data URL)
func hasInlineData(part uctypes.AIMessagePart) bool {
hasData := len(part.Data) > 0
hasURL := part.URL != "" && strings.HasPrefix(part.URL, "data:")
return hasData || hasURL
}
// extractBase64Data extracts base64 data from either the Data field or a data URLView on GitHub (pinned to a4447c1563)
Solutions
- Filter aiMsg.Parts to only text and file types before conversion
- Convert unsupported parts (e.g. tool calls) into their text/file equivalents or drop them
- Set part.Type explicitly; never rely on zero values
- Check for library version mismatches if a previously-accepted type is now rejected
Example fix
// before
msg := uctypes.AIMessage{MessageId: id, Parts: allParts}
// after
var kept []uctypes.AIMessagePart
for _, p := range allParts {
if p.Type == uctypes.AIMessagePartTypeText || p.Type == uctypes.AIMessagePartTypeFile {
kept = append(kept, p)
}
}
msg := uctypes.AIMessage{MessageId: id, Parts: kept} Defensive patterns
Strategy: type-guard
Validate before calling
var convertible []uctypes.AIMessagePart
for _, p := range aiMsg.Parts {
if p.Type == uctypes.AIMessagePartTypeText || p.Type == uctypes.AIMessagePartTypeFile {
convertible = append(convertible, p)
}
}
aiMsg.Parts = convertible Type guard
func isAnthropicConvertiblePart(p uctypes.AIMessagePart) bool {
return p.Type == uctypes.AIMessagePartTypeText || p.Type == uctypes.AIMessagePartTypeFile
} Try / catch
if err := convert(aiMsg); err != nil {
if strings.Contains(err.Error(), "unsupported part type") {
aiMsg.Parts = filterConvertibleParts(aiMsg.Parts)
return convert(aiMsg)
}
return err
} Prevention
- Filter Parts to text/file types before Anthropic conversion
- Use exported type constants; guard against "" from zero-value parts
- When new part types appear in the library, update filters before upgrading
When it happens
Trigger: Appending an AIMessagePart whose Type is not AIMessagePartTypeText or AIMessagePartTypeFile (including "" from a zero-value part or a mistyped constant) to aiMsg.Parts and converting for Anthropic.
Common situations: Reusing AIMessage parts populated for a different provider (OpenAI tool calls) without filtering; typo'd type constants; unmarshal producing empty Type; newer library versions adding part types this converter does not handle.
Related errors
- convertFileUIMessagePart expects 'file' type, got '%s'
- invalid AIMessage: %w
- convertFileAIMessagePart expects 'file' type, got '%s'
- no data available for base64 extraction
- toolResults cannot be empty
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/307f2f15c49f2ce8.
Report an issue: GitHub.