wavetermdev/waveterm · error

text/plain file part missing data

Error message

text/plain file part missing data

What it means

Indicates a text/plain file part in an AI message is missing its data payload, so the file cannot be attached or converted.

Source

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

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

// FormatAttachedDirectoryListing formats a directory listing attachment with proper encoding and deterministic suffix
func FormatAttachedDirectoryListing(directoryName, jsonContent string) string {

View on GitHub (pinned to a4447c1563)

Solutions

  1. Read the text file and pass its bytes as the data argument.
  2. Populate the URL field with a data: URL containing the text content.
  3. Skip the empty part and warn instead of calling ExtractTextData with no content.
  4. Add a pre-check: if len(data) == 0 && url == "" return/skip the part early.

Example fix

// before
part := uctypes.UIMessageDataUserFile{FileName: "a.txt", MimeType: "text/plain"}
_, err := aiutil.ExtractTextData(nil, "") // missing data
// after
content, _ := os.ReadFile("a.txt")
_, err := aiutil.ExtractTextData(content, "")
Defensive patterns

Strategy: validation

Validate before calling

func hasTextContent(data []byte, url string) bool { return len(data) > 0 || url != "" }
if !hasTextContent(part.Data, part.URL) { return fmt.Errorf("text file %q has no content", part.FileName) }

Try / catch

content, err := aiutil.ExtractTextData(data, url)
if err != nil {
    return nil, fmt.Errorf("attachment %s unusable, skipping: %w", fileName, err)
}

Prevention

When it happens

Trigger: Calling ExtractTextData (directly or via convertFileAIMessagePart/convertAIMessageTextOnly/convertAIMessageMultimodal) with data == nil/empty AND url == "" — e.g. a file part where only FileName/MimeType were set.

Common situations: Constructing UIMessageParts for text attachments without reading the file; content lost during serialization/deserialization; a client that sent the attachment metadata but failed to include the body.

Related errors


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