{"record":{"id":"4d775705cd89f8f8","repo":"Tencent/WeKnora","slug":"mineru-api-status-d-s","errorCode":null,"errorMessage":"MinerU API status %d: %s","messagePattern":"MinerU API status (.+?): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/infrastructure/docparser/mineru_converter.go","lineNumber":254,"sourceCode":"\thttpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, c.endpoint+\"/file_parse\", &body)\n\tif err != nil {\n\t\treturn \"\", nil, fmt.Errorf(\"create request: %w\", err)\n\t}\n\thttpReq.Header.Set(\"Content-Type\", writer.FormDataContentType())\n\n\tclient := utils.NewSSRFSafeHTTPClient(utils.SSRFSafeHTTPClientConfig{\n\t\tTimeout:      mineruTimeout,\n\t\tMaxRedirects: 5,\n\t})\n\tresp, err := client.Do(httpReq)\n\tif err != nil {\n\t\treturn \"\", nil, fmt.Errorf(\"HTTP request: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\trespBody, _ := io.ReadAll(resp.Body)\n\t\treturn \"\", nil, fmt.Errorf(\"MinerU API status %d: %s\", resp.StatusCode, string(respBody))\n\t}\n\n\trespBody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn \"\", nil, fmt.Errorf(\"read response body: %w\", err)\n\t}\n\n\t// Dump raw response for debugging (truncate if too large)\n\trawStr := string(respBody)\n\tif len(rawStr) > 4000 {\n\t\tlogger.Infof(context.Background(), \"[MinerU] Raw response (truncated to 4000 chars): %s ...\", rawStr[:4000])\n\t} else {\n\t\tlogger.Infof(context.Background(), \"[MinerU] Raw response: %s\", rawStr)\n\t}\n\n\t// Also pretty-print the top-level structure (without large base64 blobs)\n\tvar rawMap map[string]interface{}\n\tif err := json.Unmarshal(respBody, &rawMap); err == nil {","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/infrastructure/docparser/mineru_converter.go#L236-L272","documentation":"callFileParse in the MinerU converter performs an HTTP request to the self-hosted or cloud MinerU document-parsing service. When the service responds with any HTTP status other than 200, the converter aborts and wraps the status code plus the raw response body into this error so the caller can see exactly what the MinerU API rejected. It indicates the request reached MinerU but was refused or failed server-side.","triggerScenarios":"MinerU returns 400 (malformed multipart/file), 401/403 (bad or expired token), 404 (wrong endpoint path), 413 (file too large), 429 (rate limit), or 5xx (server-side parse failure) during callFileParse, which is invoked from Read.","commonSituations":"Wrong MINERU endpoint URL or API version path; invalid or rotated MinerU API token; uploading a file type or size MinerU rejects; MinerU pod OOM/crashing under load behind a 502/503 from the ingress.","solutions":["Read the status and body in the error: the response body usually contains MinerU's own JSON error message pinpointing the cause","If 401/403, verify the MinerU API token/credentials configured for the converter and rotate if expired","If 404, check the MinerU base URL and endpoint path against your deployed MinerU version","If 400/413, confirm the file type/size is supported and within MinerU's limits","If 429, add backoff/retry with rate limiting; if 5xx, check MinerU service health and logs"],"exampleFix":"// before\ncfg := MinerUConfig{BaseURL: \"http://mineru:8000/v1/parse\"}\n// after (align path with deployed MinerU version and valid token)\ncfg := MinerUConfig{BaseURL: os.Getenv(\"MINERU_BASE_URL\") + \"/file_parse\", Token: os.Getenv(\"MINERU_API_TOKEN\")}","handlingStrategy":"try-catch","validationCode":"if resp.StatusCode != http.StatusOK {\n    body, _ := io.ReadAll(resp.Body)\n    switch {\n    case resp.StatusCode == 401 || resp.StatusCode == 403:\n        // refresh/verify MinerU credentials before retrying\n    case resp.StatusCode == 429:\n        // back off and retry later\n    }\n}","typeGuard":"func isMinerUStatusError(err error) (int, string, bool) {\n    var e *MinerUStatusError\n    if errors.As(err, &e) { return e.StatusCode, e.Body, true }\n    return 0, \"\", false\n}","tryCatchPattern":"md, imgs, err := reader.Read(ctx, req)\nif err != nil {\n    if code, body, ok := isMinerUStatusError(err); ok && (code == 429 || code >= 500) {\n        // retry with backoff\n    }\n    return fmt.Errorf(\"parse failed: %w\", err)\n}","preventionTips":["Pin the MinerU endpoint path to your deployed MinerU version","Monitor token expiry and rotate credentials before they lapse","Alert on non-200 rates from the MinerU service","Validate file size/type against MinerU limits before submission"],"tags":["http","upstream-api","mineru","docparser"],"backgroundTag":"upstream-http-non-200","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}