wavetermdev/waveterm · error
unsupported URL protocol in file part: %s
Error message
unsupported URL protocol in file part: %s
What it means
ExtractImageUrl in pkg/aiusechat/aiutil converts AI message file parts into data URLs. If a part carries a url that is not data:, http://, or https://, it is refused with "unsupported URL protocol in file part" because the AI providers only accept those schemes for image URLs.
Source
Thrown at pkg/aiusechat/aiutil/aiutil.go:74
}
// GenerateDeterministicSuffix creates an 8-character hash from input strings
func GenerateDeterministicSuffix(inputs ...string) string {
hasher := sha256.New()
for _, input := range inputs {
hasher.Write([]byte(input))
}
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)View on GitHub (pinned to a4447c1563)
Solutions
- Use http://, https://, or a data: URL for the part's URL field
- For local files, load the bytes into the part's Data field and let ExtractImageUrl base64-encode them into a data URL
- Normalize or reject unsupported-scheme URLs before building the AI message parts
Example fix
// before
part := aiusechat.AIMessagePart{Type: "image", URL: "file:///tmp/img.png"}
// after
data, _ := os.ReadFile("/tmp/img.png")
part := aiusechat.AIMessagePart{Type: "image", Data: data, MimeType: "image/png"} Defensive patterns
Strategy: validation
Validate before calling
func validImageURL(u string) bool {
return strings.HasPrefix(u, "data:") || strings.HasPrefix(u, "http://") || strings.HasPrefix(u, "https://")
} Try / catch
url, err := aiutil.ExtractImageUrl(data, url, mimeType)
if err != nil {
return fmt.Errorf("image part rejected: %w", err)
} Prevention
- Always use http/https/data URLs for AI image parts
- Read local files into the Data field instead of file:// URLs
- Validate URLs at message-construction time, before calling the provider
When it happens
Trigger: An AIMessagePart of type file/image whose URL field uses ftp://, file://, a relative path, or a protocol-relative //host URL; the check runs in ExtractImageUrl called from convertFileAIMessagePart / convertAIMessageMultimodal.
Common situations: Feeding local file paths as URLs instead of reading bytes into the Data field; passing URLs from vendor docs using unsupported schemes; upstream chat history containing non-http image links.
Related errors
- invalid url: %w
- url must be https or data URL, got %q
- Image too large (>5MB)
- Unsupported or invalid image type: ${blob.type}
- Invalid CSS color: ${String(color)}
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/6301e4e228b41134.
Report an issue: GitHub.