Tencent/WeKnora · error

download zip status %d

Error message

download zip status %d

What it means

The ZIP download request returned an HTTP status other than 200, and downloadAndExtractZip rejects it with 'download zip status %d' (mineru_cloud_converter.go:366). Typical statuses: 403/404 for expired or revoked result URLs, 401 for auth problems, 5xx for storage-side errors. The body is not attempted because it won't contain a valid ZIP.

Source

Thrown at internal/infrastructure/docparser/mineru_cloud_converter.go:366

	return md, imageRefs, nil
}

// --- ZIP handling ---

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") {

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Check the status code in the message: 403/404 means the link expired or results were purged — re-run the batch conversion for a fresh full_zip_url.
  2. For 429, back off and retry with jitter; respect the storage service rate limits.
  3. For 5xx, retry after a delay; if persistent, check MinerU Cloud service health.
  4. Download results promptly after the task reaches done state to avoid link expiry.

Example fix

// before
if resp.StatusCode != http.StatusOK {
    return "", nil, fmt.Errorf("download zip status %d", resp.StatusCode)
}
// after — include body hint for diagnosis
if resp.StatusCode != http.StatusOK {
    b, _ := io.ReadAll(io.LimitReader(resp.Body, 512))
    return "", nil, fmt.Errorf("download zip status %d: %s", resp.StatusCode, string(b))
}
Defensive patterns

Strategy: try-catch

Validate before calling

if item.FullZipURL == "" {
    return errors.New("no full_zip_url to download")
}

Try / catch

md, images, err := pollBatchResult(ctx, batchID)
if err != nil {
    var statusErr *ZipDownloadStatusError
    if errors.As(err, &statusErr) && (statusErr.Code == 403 || statusErr.Code == 404) {
        // link expired / results purged: re-run the batch conversion
        return resubmitBatch(ctx, doc)
    }
    if statusErr != nil && statusErr.Code == 429 {
        time.Sleep(backoff)
        return pollBatchResult(ctx, batchID)
    }
    return err
}

Prevention

When it happens

Trigger: extractDoneResult -> downloadAndExtractZip GETs full_zip_url and receives e.g. 403 (presigned URL expired), 404 (results purged), 429 (rate limited), or 5xx from the storage backend.

Common situations: Polling results long after task completion once MinerU Cloud expires download links; sharing/leaking the URL across environments with different access; storage outage returning 5xx; hammering the endpoint causing 429.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/f3298f9a47b0d678. Report an issue: GitHub.