Tencent/WeKnora · error
read zip body: %w
Error message
read zip body: %w
What it means
downloadAndExtractZip downloads the result ZIP produced by an async MinerU parsing job and reads it fully into memory with io.ReadAll. This error wraps any failure while reading the HTTP response body (network reset mid-transfer, timeout, context cancellation, truncated connection). It does not indicate the ZIP itself is corrupt — only that the raw bytes could not be downloaded.
Source
Thrown at internal/infrastructure/docparser/mineru_cloud_converter.go:371
var imgRefPattern = regexp.MustCompile(`!\[[^\]]*\]\(([^)]+)\)`)
func downloadAndExtractZip(zipURL string) (string, []types.ImageRef, error) {
if err := utils.ValidateURLForSSRF(zipURL); err != nil {
return "", nil, fmt.Errorf("zip URL blocked by SSRF check: %v", err)
}
client := utils.NewSSRFSafeHTTPClient(utils.SSRFSafeHTTPClientConfig{Timeout: 120 * time.Second, MaxRedirects: 5})
resp, err := client.Get(zipURL)
if err != nil {
return "", nil, fmt.Errorf("download zip: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", nil, fmt.Errorf("download zip status %d", resp.StatusCode)
}
zipData, err := io.ReadAll(resp.Body)
if err != nil {
return "", nil, fmt.Errorf("read zip body: %w", err)
}
zr, err := zip.NewReader(bytes.NewReader(zipData), int64(len(zipData)))
if err != nil {
return "", nil, fmt.Errorf("open zip: %w", err)
}
// Find .md files
var mdFiles []string
entries := make(map[string]*zip.File)
for _, f := range zr.File {
entries[f.Name] = f
if strings.HasSuffix(f.Name, ".md") {
mdFiles = append(mdFiles, f.Name)
}
}
if len(mdFiles) == 0 {
return "", nil, fmt.Errorf("no .md file found in zip")View on GitHub (pinned to 988cbb0330)
Solutions
- Retry downloadAndExtractZip with backoff — transient network failures usually succeed on a second attempt.
- Check the caller's ctx deadline; increase it if the ZIP is large relative to the timeout.
- Verify any proxy/load balancer between the service and MinerU allows large streaming responses (raise idle/response timeouts, disable response buffering limits).
- Check upstream logs for the wrapped cause (%w) to distinguish reset vs timeout vs cancellation.
Example fix
// before
zipData, err := io.ReadAll(resp.Body)
if err != nil {
return "", nil, fmt.Errorf("read zip body: %w", err)
}
// after
zipData, err := io.ReadAll(resp.Body)
if err != nil {
if ctx.Err() != nil {
return "", nil, fmt.Errorf("read zip body: canceled: %w", ctx.Err())
}
return "", nil, fmt.Errorf("read zip body: %w", err) // retryable
} Defensive patterns
Strategy: retry
Try / catch
md, _, err := conv.Read(ctx, req)
if err != nil && strings.Contains(err.Error(), "read zip body") {
// transient network: retry with backoff, respecting ctx
md, _, err = conv.Read(ctx, req)
} Prevention
- Set generous context deadlines sized to expected ZIP sizes
- Retry idempotent download operations with exponential backoff
- Monitor proxy/load-balancer response-size and timeout limits
- Check ctx.Err() after failures to distinguish cancellation from network errors
When it happens
Trigger: The HTTP GET that fetches the finished job's ZIP returns 200 but the response body fails during io.ReadAll(resp.Body): connection reset, unexpected EOF, context deadline exceeded while streaming a large ZIP.
Common situations: Large result ZIPs from big PDFs dropped by proxies/load balancers with idle-timeout limits; caller context canceled because the user request timed out upstream; unstable network between the service and the MinerU result storage endpoint.
Related errors
- read body failed: %w
- read response body: %w
- read body: %w
- read poll response body: %w
- read response body: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/e10cdc6f83230da8.
Report an issue: GitHub.