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

  1. Ensure part.Type == uctypes.AIMessagePartTypeFile before the part enters the file path
  2. Use the exported constant rather than a raw string literal for Type
  3. 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

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


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