wavetermdev/waveterm · error

text/plain file with URL not supported (must be fetched and

Error message

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

What it means

Anthropic document blocks for text/plain content require inline base64 data or a Files API file_id; the library does not fetch remote URLs on the caller's behalf. A text/plain part that carries an http/https URL instead of embedded data is rejected because there is no inline content to send.

Source

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

				}
				decoded, err := base64.StdEncoding.DecodeString(base64Data)
				if err != nil {
					return nil, fmt.Errorf("failed to decode base64 data: %w", err)
				}
				textData = string(decoded)
			}
			return &anthropicMessageContentBlock{
				Type: "document",
				Source: &anthropicSource{
					Type:      "text",
					Data:      textData,
					MediaType: part.MimeType,
					FileName:  part.FileName,
				},
			}, nil
		} else {
			// HTTP/HTTPS URL → not supported inline, would need to fetch
			return nil, fmt.Errorf("text/plain file with URL not supported (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("unsupported media type '%s' (must be uploaded to Files API and sent as file_id)", part.MimeType)
	}
}

// ConvertToUIMessage converts an anthropicChatMessage to a UIMessage
func (m *anthropicChatMessage) ConvertToUIMessage() *uctypes.UIMessage {
	var parts []uctypes.UIMessagePart

	// Iterate over all content blocks
	for _, block := range m.Content {
		switch block.Type {
		case "text":
			// Convert text blocks to UIMessagePart
			parts = append(parts, uctypes.UIMessagePart{

View on GitHub (pinned to a4447c1563)

Solutions

  1. Fetch the URL yourself (http.Get), read the body, base64-encode it, and supply it as a data: URL
  2. Upload the file to the Anthropic Files API and reference it by file_id
  3. Inline the text content directly as base64 data in the part

Example fix

// before
part.URL = "https://example.com/notes.txt"
// after
resp, _ := http.Get(part.URL)
body, _ := io.ReadAll(resp.Body)
part.URL = "data:text/plain;base64," + base64.StdEncoding.EncodeToString(body)
Defensive patterns

Strategy: fallback

Validate before calling

if strings.HasPrefix(part.MimeType, "text/plain") && strings.HasPrefix(part.URL, "http") && !strings.HasPrefix(part.URL, "data:") {
    // fetch and convert to base64 first
}

Try / catch

blocks, err := anthropic.ConvertAIMessageToAnthropicChatMessage(msg)
if err != nil && strings.Contains(err.Error(), "text/plain file with URL not supported") {
    body := fetchAndBase64(part.URL) // fallback: fetch yourself
    part.URL = "data:text/plain;base64," + body
}

Prevention

When it happens

Trigger: ConvertFileAIMessagePart with a part whose MimeType starts with 'text/plain' and part.URL is an http:// or https:// URL (rather than a data: URL) and no base64 data is provided.

Common situations: Passing a link to a hosted text/CSV/log file expecting the SDK to download it; migrating code from another provider that fetched URLs server-side.

Related errors


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