wavetermdev/waveterm · warning

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 data)

What it means

ExtractTextData only accepts text content as raw bytes or as a data: URL. If the url is a remote reference (http/https or other scheme) the function refuses to process it because it does not fetch network resources. The text file is effectively 'dropped' from the message.

Source

Thrown at pkg/aiusechat/aiutil/aiutil.go:98

		return fmt.Sprintf("data:%s;base64,%s", mimeType, base64Data), nil
	}
	return "", fmt.Errorf("file part missing both url and data")
}

// ExtractTextData extracts text data from either Data field or URL field (data: URLs only)
func ExtractTextData(data []byte, url string) ([]byte, error) {
	if len(data) > 0 {
		return data, nil
	}
	if url != "" {
		if strings.HasPrefix(url, "data:") {
			_, decodedData, err := utilfn.DecodeDataURL(url)
			if err != nil {
				return nil, fmt.Errorf("failed to decode data URL for text/plain file: %w", err)
			}
			return decodedData, nil
		}
		return nil, fmt.Errorf("dropping text/plain file with URL (must be fetched and converted to data)")
	}
	return nil, fmt.Errorf("text/plain file part missing data")
}

// FormatAttachedTextFile formats a text file attachment with proper encoding and deterministic suffix
func FormatAttachedTextFile(fileName string, textContent []byte) string {
	if fileName == "" {
		fileName = "untitled.txt"
	}

	encodedFileName := strings.ReplaceAll(fileName, `"`, """)
	quotedFileName := strconv.Quote(encodedFileName)

	textStr := string(textContent)
	deterministicSuffix := GenerateDeterministicSuffix(textStr, fileName)
	return fmt.Sprintf("<AttachedTextFile_%s file_name=%s>\n%s\n</AttachedTextFile_%s>", deterministicSuffix, quotedFileName, textStr, deterministicSuffix)
}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Fetch the URL yourself (http.Get or equivalent) and pass the response bytes via the data parameter.
  2. Convert the fetched bytes to a data: URL before passing, if you must keep the URL parameter shape.
  3. Change the client to upload the text content inline (base64 data URL) instead of sending a link.
  4. Handle the error by dropping the attachment and appending a note to the message text.

Example fix

// before
content, err := aiutil.ExtractTextData(nil, "https://example.com/notes.txt") // dropped
// after
resp, _ := http.Get("https://example.com/notes.txt")
body, _ := io.ReadAll(resp.Body)
content, err := aiutil.ExtractTextData(body, "")
Defensive patterns

Strategy: fallback

Validate before calling

func needsFetch(u string) bool { return u != "" && !strings.HasPrefix(u, "data:") }

Type guard

func isDataURL(u string) bool { return strings.HasPrefix(u, "data:") }

Try / catch

content, err := aiutil.ExtractTextData(data, url)
if err != nil && strings.Contains(err.Error(), "dropping text/plain") {
    resp, ferr := http.Get(url)
    if ferr == nil {
        body, _ := io.ReadAll(resp.Body)
        content, err = aiutil.ExtractTextData(body, "")
    }
}

Prevention

When it happens

Trigger: Passing ExtractTextData a URL like "https://example.com/notes.txt" or any non-data: URL with empty data. Callers (convertFileAIMessagePart, convertAIMessageTextOnly, convertAIMessageMultimodal) hit this when an attached text file part carries a remote URL instead of inline content.

Common situations: Client uploads a file reference/link rather than file content; frontend integration forwards a CDN URL for text files; migrating from providers that accept remote file URLs to this message format that requires inline data.

Related errors


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