wavetermdev/waveterm · error
convertFileAIMessagePart expects 'file' type, got '%s'
Error message
convertFileAIMessagePart expects 'file' type, got '%s'
What it means
convertFileAIMessagePart is an internal helper that only handles AIMessageParts whose Type is AIMessagePartTypeFile. It rejects anything else up front, so this error indicates the public converter dispatched a non-file part into the file branch — an internal dispatch inconsistency or a caller constructing parts with a wrong Type value.
Source
Thrown at pkg/aiusechat/anthropic/anthropic-convertmessage.go:539
data := parts[1]
// Check if it's already base64 encoded: data:mediatype;base64,<data>
if strings.Contains(header, ";base64") {
// Already base64 encoded
return data, nil
} else {
// Raw data that needs base64 encoding: data:mediatype,<raw_data>
return base64.StdEncoding.EncodeToString([]byte(data)), nil
}
}
return "", errors.New("no data available for base64 extraction")
}
// convertFileAIMessagePart converts a file AIMessagePart to anthropicMessageContentBlock
func convertFileAIMessagePart(part uctypes.AIMessagePart) (*anthropicMessageContentBlock, error) {
if part.Type != uctypes.AIMessagePartTypeFile {
return nil, fmt.Errorf("convertFileAIMessagePart expects 'file' type, got '%s'", part.Type)
}
if err := part.Validate(); err != nil {
return nil, err
}
// Validate URL protocol if URL is provided - only allow data:, http:, https:
if part.URL != "" {
if !strings.HasPrefix(part.URL, "data:") &&
!strings.HasPrefix(part.URL, "http://") &&
!strings.HasPrefix(part.URL, "https://") {
return nil, fmt.Errorf("unsupported URL protocol in file part: %s", part.URL)
}
}
// Branch on mimetype to determine block type and constraints
switch {
case strings.HasPrefix(part.MimeType, "image/"):View on GitHub (pinned to a4447c1563)
Solutions
- Ensure part.Type == uctypes.AIMessagePartTypeFile before the part enters the file path
- Use the exported constant rather than a raw string literal for Type
- Fix the dispatch in ConvertAIMessageToAnthropicChatMessage callers if non-file parts are being routed here
Example fix
// before
part := uctypes.AIMessagePart{Type: "file", MimeType: "image/png", Data: imgBytes} // literal differs from constant
// after
part := uctypes.AIMessagePart{Type: uctypes.AIMessagePartTypeFile, MimeType: "image/png", Data: imgBytes} Defensive patterns
Strategy: type-guard
Validate before calling
func isFileAIMessagePart(p uctypes.AIMessagePart) bool { return p.Type == uctypes.AIMessagePartTypeFile }
if !isFileAIMessagePart(part) { return fmt.Errorf("not a file part: %q", part.Type) } Type guard
func isFileAIMessagePart(p uctypes.AIMessagePart) bool {
return p.Type == uctypes.AIMessagePartTypeFile
} Try / catch
if err := convert(aiMsg); err != nil {
if strings.Contains(err.Error(), "convertFileAIMessagePart expects 'file'") {
log.Printf("non-file part reached file converter: %+v", part)
return nil // skip or reroute
}
return err
} Prevention
- Set Type via uctypes.AIMessagePartTypeFile, never raw literals
- Confirm dispatch logic routes only file parts into file converters
- Add tests asserting each part type takes its intended conversion branch
When it happens
Trigger: An AIMessagePart reaching convertFileAIMessagePart with Type != AIMessagePartTypeFile (e.g. "", "text", or an unknown type string), via ConvertAIMessageToAnthropicChatMessage's file case.
Common situations: Custom part types added downstream without updating the converter; type constants defined with differing string values between packages; reflection/manual part construction that skips Type.
Related errors
- convertFileUIMessagePart expects 'file' type, got '%s'
- invalid AIMessage: %w
- part %d: unsupported part type '%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/40265da8a2d59905.
Report an issue: GitHub.