wavetermdev/waveterm · error
file part missing both url and data
Error message
file part missing both url and data
What it means
ExtractImageUrl builds the image URL for a file message part. It throws this error when a file part has neither a usable URL nor any raw bytes, so there is no way to construct an image reference for the model. This guards the AI message conversion path from emitting empty/dead image parts.
Source
Thrown at pkg/aiusechat/aiutil/aiutil.go:82
hash := hasher.Sum(nil)
return hex.EncodeToString(hash)[:8]
}
// ExtractImageUrl extracts an image URL from either URL field (http/https/data) or raw Data
func ExtractImageUrl(data []byte, url, mimeType string) (string, error) {
if url != "" {
if !strings.HasPrefix(url, "data:") &&
!strings.HasPrefix(url, "http://") &&
!strings.HasPrefix(url, "https://") {
return "", fmt.Errorf("unsupported URL protocol in file part: %s", url)
}
return url, nil
}
if len(data) > 0 {
base64Data := base64.StdEncoding.EncodeToString(data)
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")View on GitHub (pinned to a4447c1563)
Solutions
- Populate either the URL field (http/https/data:) or the raw Data bytes before building the message part.
- Fetch the file content and pass its bytes as data (it will be base64-encoded into a data: URL automatically).
- If the part is unrecoverable, drop the file part from the message instead of passing an empty one.
- Wrap the call in error handling and skip/replace the part with a text note explaining the attachment failed.
Example fix
// before
part := &uctypes.UIMessagePart{Type: "file", Data: uctypes.UIMessageDataUserFile{FileName: "img.png", MimeType: "image/png"}}
url, err := aiutil.ExtractImageUrl(nil, "", "image/png") // error
// after
fileData, _ := os.ReadFile("img.png")
url, err := aiutil.ExtractImageUrl(fileData, "", "image/png") // data:image/png;base64,... Defensive patterns
Strategy: validation
Validate before calling
func validImagePart(data []byte, url string) bool {
if len(data) > 0 { return true }
return url != "" && (strings.HasPrefix(url, "data:") || strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://"))
}
// call ExtractImageUrl only if validImagePart(data, url) Type guard
func hasImageSource(data []byte, url string) bool { return len(data) > 0 || url != "" } Try / catch
url, err := aiutil.ExtractImageUrl(data, url, mime)
if err != nil {
log.Printf("skipping image part: %v", err)
return nil // drop or substitute part
} Prevention
- Always read file bytes into Data before constructing file parts unless you have a valid http(s)/data URL
- Add a constructor helper that requires at least one of url/data at creation time
- Unit-test message-building code with parts missing each field
When it happens
Trigger: Calling ExtractImageUrl (via convertFileAIMessagePart/convertAIMessageMultimodal) with a UIMessageDataUserFile-style part where url == "" and len(data) == 0. Note: if url is set but uses an unsupported protocol, a different error (unsupported URL protocol) is returned instead.
Common situations: Constructing AI message parts programmatically and forgetting to read the file bytes into Data; a previously-attached file whose URL was revoked or never populated; serialization round-trips that drop the Data field.
Related errors
- integer overflow
- adding file %s: %w
- text/plain file part missing data
- input is required
- invalid input format: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/5c9f1dba11b25e62.
Report an issue: GitHub.