Tencent/WeKnora · error
read body: %w
Error message
read body: %w
What it means
This error wraps an I/O failure while reading the remote image response body through an io.LimitReader capped at maxRemoteImageSize+1 bytes. It signals the body stream broke mid-read (connection reset, unexpected EOF, timeout) rather than a size violation.
Source
Thrown at internal/infrastructure/docparser/image_resolver.go:1041
}
// 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 {
return nil, "", fmt.Errorf("downloaded data is not an image (sniffed: %s)", detected)
}
}
return body, mimeType, nil
}
View on GitHub (pinned to 988cbb0330)
Solutions
- Unwrap the error — connection reset/unexpected EOF usually means retry with backoff
- Increase the download timeout/context budget for large images
- Check proxy/LB idle-timeout settings that may cut long transfers
- Skip persistently failing image URLs rather than blocking document processing
Example fix
// before
limited := io.LimitReader(resp.Body, maxRemoteImageSize+1)
body, err := io.ReadAll(limited)
if err != nil { return nil, "", fmt.Errorf("read body: %w", err) }
// after
limited := io.LimitReader(resp.Body, maxRemoteImageSize+1)
body, err := io.ReadAll(limited)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
return nil, "", fmt.Errorf("read body (deadline exceeded): %w", err)
}
return nil, "", fmt.Errorf("read body: %w", err)
} Defensive patterns
Strategy: retry
Validate before calling
// ensure enough time budget for large images before fetching
if deadline, ok := ctx.Deadline(); ok && time.Until(deadline) < 10*time.Second {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
} Try / catch
data, mimeType, err := downloadImage(ctx, client, remoteURL)
if err != nil {
var ne net.Error
if errors.As(err, &ne) && (ne.Timeout() || strings.Contains(err.Error(), "unexpected EOF")) {
// transient truncation: retry once with backoff
time.Sleep(time.Second)
return downloadImage(ctx, client, remoteURL)
}
return nil, "", fmt.Errorf("read body: %w", err)
} Prevention
- Set generous context timeouts for large image downloads
- Retry on transient read errors (EOF, connection reset) with backoff
- Check proxy/LB idle timeouts against expected image sizes
- Cap image size on the client side so downloads finish quickly
When it happens
Trigger: io.ReadAll on the limited body fails: connection reset by peer, unexpected EOF, TLS truncation, or context deadline exceeded while streaming a large image.
Common situations: Flaky image hosts dropping connections on large files, proxies terminating long downloads, context timeout too short for big images, network interruptions mid-transfer.
Related errors
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/67c02dad3cd6db1c.
Report an issue: GitHub.