{"record":{"id":"f3298f9a47b0d678","repo":"Tencent/WeKnora","slug":"download-zip-status-d","errorCode":null,"errorMessage":"download zip status %d","messagePattern":"download zip status (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/infrastructure/docparser/mineru_cloud_converter.go","lineNumber":366,"sourceCode":"\treturn md, imageRefs, nil\n}\n\n// --- ZIP handling ---\n\nvar imgRefPattern = regexp.MustCompile(`!\\[[^\\]]*\\]\\(([^)]+)\\)`)\n\nfunc downloadAndExtractZip(zipURL string) (string, []types.ImageRef, error) {\n\tif err := utils.ValidateURLForSSRF(zipURL); err != nil {\n\t\treturn \"\", nil, fmt.Errorf(\"zip URL blocked by SSRF check: %v\", err)\n\t}\n\tclient := utils.NewSSRFSafeHTTPClient(utils.SSRFSafeHTTPClientConfig{Timeout: 120 * time.Second, MaxRedirects: 5})\n\tresp, err := client.Get(zipURL)\n\tif err != nil {\n\t\treturn \"\", nil, fmt.Errorf(\"download zip: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn \"\", nil, fmt.Errorf(\"download zip status %d\", resp.StatusCode)\n\t}\n\n\tzipData, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn \"\", nil, fmt.Errorf(\"read zip body: %w\", err)\n\t}\n\n\tzr, err := zip.NewReader(bytes.NewReader(zipData), int64(len(zipData)))\n\tif err != nil {\n\t\treturn \"\", nil, fmt.Errorf(\"open zip: %w\", err)\n\t}\n\n\t// Find .md files\n\tvar mdFiles []string\n\tentries := make(map[string]*zip.File)\n\tfor _, f := range zr.File {\n\t\tentries[f.Name] = f\n\t\tif strings.HasSuffix(f.Name, \".md\") {","sourceCodeStart":348,"sourceCodeEnd":384,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/infrastructure/docparser/mineru_cloud_converter.go#L348-L384","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","For 429, back off and retry with jitter; respect the storage service rate limits.","For 5xx, retry after a delay; if persistent, check MinerU Cloud service health.","Download results promptly after the task reaches done state to avoid link expiry."],"exampleFix":"// before\nif resp.StatusCode != http.StatusOK {\n    return \"\", nil, fmt.Errorf(\"download zip status %d\", resp.StatusCode)\n}\n// after — include body hint for diagnosis\nif resp.StatusCode != http.StatusOK {\n    b, _ := io.ReadAll(io.LimitReader(resp.Body, 512))\n    return \"\", nil, fmt.Errorf(\"download zip status %d: %s\", resp.StatusCode, string(b))\n}","handlingStrategy":"try-catch","validationCode":"if item.FullZipURL == \"\" {\n    return errors.New(\"no full_zip_url to download\")\n}","typeGuard":null,"tryCatchPattern":"md, images, err := pollBatchResult(ctx, batchID)\nif err != nil {\n    var statusErr *ZipDownloadStatusError\n    if errors.As(err, &statusErr) && (statusErr.Code == 403 || statusErr.Code == 404) {\n        // link expired / results purged: re-run the batch conversion\n        return resubmitBatch(ctx, doc)\n    }\n    if statusErr != nil && statusErr.Code == 429 {\n        time.Sleep(backoff)\n        return pollBatchResult(ctx, batchID)\n    }\n    return err\n}","preventionTips":["Download the ZIP immediately once state=done to beat link expiry.","Branch on the status code: 403/404 re-submit, 429 back off, 5xx retry.","Keep batch IDs short-lived in your own storage since MinerU results expire."],"tags":["http","download","expired-url","go","cloud-storage"],"backgroundTag":"http-non-200-status","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}