Tencent/WeKnora · error
non-image content type: %s
Error message
non-image content type: %s
What it means
This error is returned when the remote image's Content-Type header is neither an image/* type nor application/octet-stream. It is a safety check preventing storage of HTML error pages, text, or other non-image payloads as images.
Source
Thrown at internal/infrastructure/docparser/image_resolver.go:1034
if err != nil {
return nil, "", fmt.Errorf("HTTP GET: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, "", fmt.Errorf("unexpected status %d", resp.StatusCode)
}
// Determine MIME type from Content-Type header.
ct := resp.Header.Get("Content-Type")
mimeType, _, _ = mime.ParseMediaType(ct)
if mimeType == "" {
mimeType = "application/octet-stream"
}
// Only allow image content types (or octet-stream which we sniff later).
if !strings.HasPrefix(mimeType, "image/") && mimeType != "application/octet-stream" {
return nil, "", fmt.Errorf("non-image content type: %s", mimeType)
}
// Read body with size limit.
limited := io.LimitReader(resp.Body, maxRemoteImageSize+1)
body, err := io.ReadAll(limited)
if err != nil {
return nil, "", fmt.Errorf("read body: %w", err)
}
if len(body) > maxRemoteImageSize {
return nil, "", fmt.Errorf("image exceeds %d bytes limit", maxRemoteImageSize)
}
// If MIME was octet-stream, sniff the real type from body.
if mimeType == "application/octet-stream" {
detected := http.DetectContentType(body)
if strings.HasPrefix(detected, "image/") {
mimeType = detected
} else {View on GitHub (pinned to 988cbb0330)
Solutions
- Verify the URL actually serves an image (curl -I to inspect Content-Type)
- Skip images whose host returns HTML error pages with 200 status
- If the server sends a wrong-but-known type, fix the server's Content-Type header
- Rely on octet-stream sniffing already implemented for servers omitting the type
Example fix
// before
if !strings.HasPrefix(mimeType, "image/") && mimeType != "application/octet-stream" {
return nil, "", fmt.Errorf("non-image content type: %s", mimeType)
}
// after
// sniff first 512 bytes to rescue wrong headers
cmp := http.DetectContentType(body[:minInt(512, len(body))])
if !strings.HasPrefix(mimeType, "image/") && !strings.HasPrefix(cmp, "image/") {
return nil, "", fmt.Errorf("non-image content type: %s", mimeType)
} Defensive patterns
Strategy: validation
Validate before calling
// check Content-Type before downloading the full body
resp, err := http.Head(imgURL)
if err != nil { return err }
ct := resp.Header.Get("Content-Type")
if !strings.HasPrefix(ct, "image/") && ct != "application/octet-stream" {
return fmt.Errorf("skipping non-image resource: %s", ct)
} Try / catch
data, mimeType, err := downloadImage(ctx, client, remoteURL)
if err != nil {
if strings.Contains(err.Error(), "non-image content type") {
log.Warn("skipping non-image response", "url", remoteURL)
return nil, "", errRemoteImageSkipped
}
return nil, "", err
} Prevention
- HEAD-preflight image URLs and check Content-Type before full download
- Treat 200-with-HTML responses as dead links and skip them
- Use content sniffing (http.DetectContentType) as a fallback for wrong headers
- Keep the octet-stream allowance for servers that omit Content-Type
When it happens
Trigger: downloadImage receives a response whose Content-Type is e.g. text/html (soft-404/error page), application/json, or text/plain.
Common situations: Dead image links returning HTML error pages with 200 status, CDNs serving JSON error bodies, misconfigured servers sending wrong Content-Type headers, authenticated pages redirecting to login HTML.
Related errors
- invalid image content type: %s
- cannot run workspace script %q for skill %q: no installed sk
- fetch feed %s: %w
- download: %w
- create request: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/2d02ff27a32f903b.
Report an issue: GitHub.