wavetermdev/waveterm · error

dropping text/plain file with URL (must be fetched and conve

Error message

dropping text/plain file with URL (must be fetched and converted to base64 or uploaded to Files API)

What it means

text/plain file parts are only supported when embedded inline as a data: URL (decoded to an Anthropic plain-text document source). The Anthropic API has no URL-based text document form this converter can use, so a text/plain part carrying an http(s) URL is rejected with this error telling you to fetch the content yourself and inline it, or upload via the Files API.

Source

Thrown at pkg/aiusechat/anthropic/anthropic-convertmessage.go:449

			if len(parts) != 2 {
				return nil, errors.New("invalid data URL format")
			}
			// Decode base64 data
			textData, err := base64.StdEncoding.DecodeString(parts[1])
			if err != nil {
				return nil, fmt.Errorf("failed to decode base64 data: %w", err)
			}
			return &anthropicMessageContentBlock{
				Type: "document",
				Source: &anthropicSource{
					Type:      "text",
					Data:      string(textData),
					MediaType: "text/plain",
				},
			}, nil
		} else {
			// HTTP/HTTPS URL → not supported inline, would need to fetch
			return nil, fmt.Errorf("dropping text/plain file with URL (must be fetched and converted to base64 or uploaded to Files API)")
		}

	default:
		// Other media types → not supported inline, must upload and use file_id
		return nil, fmt.Errorf("dropping file with unsupported media type '%s' (must be uploaded to Files API and sent as file_id)", p.MediaType)
	}

}

// convertAIMessageToAnthropicChatMessage converts an AIMessage to anthropicChatMessage
// These messages are ALWAYS role "user"
func ConvertAIMessageToAnthropicChatMessage(aiMsg uctypes.AIMessage) (*anthropicChatMessage, error) {
	if err := aiMsg.Validate(); err != nil {
		return nil, fmt.Errorf("invalid AIMessage: %w", err)
	}

	var contentBlocks []anthropicMessageContentBlock

View on GitHub (pinned to a4447c1563)

Solutions

  1. Fetch the URL server-side, then send the content as a data:text/plain;base64,... data URL
  2. Upload the file to the Anthropic Files API and reference it by file_id
  3. Inline the text directly as a text part (uctypes text part) instead of a file part

Example fix

// before
part := uctypes.UIMessagePart{Type: "file", MediaType: "text/plain", URL: "https://cdn.example.com/notes.txt"}
// after
body, _ := http.Get(part.URL) // fetch and inline
b64 := base64.StdEncoding.EncodeToString(body)
part := uctypes.UIMessagePart{Type: "file", MediaType: "text/plain", URL: "data:text/plain;base64," + b64}
Defensive patterns

Strategy: fallback

Validate before calling

if p.MediaType == "text/plain" && !strings.HasPrefix(p.URL, "data:") {
    // fetch and inline, or convert to a text part, before calling the API
}

Type guard

func isSupportedTextFilePart(p uctypes.UIMessagePart) bool {
    return p.MediaType != "text/plain" || strings.HasPrefix(p.URL, "data:")
}

Try / catch

if err := convert(msg); err != nil {
    if strings.Contains(err.Error(), "dropping text/plain file with URL") {
        body, ferr := http.Get(p.URL)
        if ferr == nil { return convert(withDataURL(msg, body)) }
    }
    return err
}

Prevention

When it happens

Trigger: Creating a UIMessagePart{Type:"file", MediaType:"text/plain", URL:"https://..."} and sending it through ConvertUIMessageToAnthropicChatMessage — the error fires in the else branch at anthropic-convertmessage.go:447-450.

Common situations: Pointing at a raw .txt/.md/.csv file hosted on S3/CDN; passing a chat file attachment that the client stored as an http URL; migrating from OpenAI-style converters where URL text files were accepted.

Related errors


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