Tencent/WeKnora · error
download: %w
Error message
download: %w
What it means
This error wraps any failure from downloadImage while fetching a remote image, including request creation, HTTP transport errors, non-200 statuses, bad content types, oversized bodies, and read errors. It is the generic download stage failure in fetchAndStoreRemoteImage.
Source
Thrown at internal/infrastructure/docparser/image_resolver.go:792
// two syntaxes.
func fetchAndStoreRemoteImage(
ctx context.Context,
client *http.Client,
fileSvc interfaces.FileService,
tenantID uint64,
imgURL string,
) (*remoteImageResult, error) {
whitelisted := isWhitelistedImageHost(imgURL)
if !whitelisted {
if err := secutils.ValidateURLForSSRF(imgURL); err != nil {
return nil, fmt.Errorf("blocked by SSRF policy: %w", err)
}
}
data, mimeType, err := downloadImage(ctx, client, imgURL)
if err != nil {
return nil, fmt.Errorf("download: %w", err)
}
if isIconImage(data) {
return nil, errRemoteImageIsIcon
}
if whitelisted {
return &remoteImageResult{MimeType: mimeType, KeepOriginalURL: true}, nil
}
ext := extFromMime(mimeType)
if ext == "" {
ext = extFromURLPath(imgURL)
}
if ext == "" {
ext = ".png" // safe default
}
servingURL, err := fileSvc.SaveBytes(ctx, data, tenantID, uuid.New().String()+ext, false)View on GitHub (pinned to 988cbb0330)
Solutions
- Unwrap the error to see the underlying cause (HTTP GET vs status vs content-type)
- Verify the image URL is alive and publicly reachable (curl -I)
- Check egress/proxy configuration and DNS in the deployment environment
- Confirm the image is within maxRemoteImageSize and served with an image Content-Type
Example fix
// before
data, mimeType, err := downloadImage(ctx, client, imgURL)
if err != nil { return nil, fmt.Errorf("download: %w", err) }
// after
data, mimeType, err := downloadImage(ctx, client, imgURL)
if err != nil {
log.Warn("remote image download failed", "url", imgURL, "err", err) // record URL for diagnosis
return nil, fmt.Errorf("download: %w", err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// preflight reachability and content type
resp, err := http.Head(imgURL)
if err != nil {
return fmt.Errorf("image unreachable: %w", err)
}
if resp.StatusCode != 200 || !strings.HasPrefix(resp.Header.Get("Content-Type"), "image/") {
return fmt.Errorf("not a fetchable image: %d %s", resp.StatusCode, resp.Header.Get("Content-Type"))
} Try / catch
res, err := resolver.fetchAndStoreRemoteImage(ctx, imgURL, tenantID)
if err != nil {
if strings.HasPrefix(err.Error(), "download:") {
// classify inner cause: SSRF/status/timeout/size
log.Warn("remote image skipped", "url", imgURL, "cause", err)
return nil // skip image, keep processing document
}
return err
} Prevention
- Preflight HEAD requests to validate image URLs before download
- Set sensible timeouts on the SSRF-safe client
- Handle hotlink-protected hosts with proper headers or skip them
- Log the full wrapped chain to identify the failing stage
When it happens
Trigger: downloadImage returns an error for the given URL: DNS failure, connection refused/timeout, non-200 status, non-image Content-Type, or body exceeding maxRemoteImageSize.
Common situations: Image host is down or slow, hotlink protection returning 403, dead image URLs in documents, images larger than the configured size cap, network egress blocked in the deployment environment.
Related errors
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/781e92337bb30522.
Report an issue: GitHub.