{"record":{"id":"543c294a8a6c9002","repo":"Tencent/WeKnora","slug":"decode-poll-response-w","errorCode":null,"errorMessage":"decode poll response: %w","messagePattern":"decode poll response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/infrastructure/docparser/mineru_cloud_converter.go","lineNumber":288,"sourceCode":"\tfor k, v := range headers {\n\t\thttpReq.Header.Set(k, v)\n\t}\n\n\tclient := utils.NewSSRFSafeHTTPClient(utils.SSRFSafeHTTPClientConfig{Timeout: 30 * time.Second, MaxRedirects: 5})\n\tresp, err := client.Do(httpReq)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\trespBody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read poll response body: %w\", err)\n\t}\n\n\tvar pollResp batchPollResponse\n\tif err := json.Unmarshal(respBody, &pollResp); err != nil {\n\t\treturn nil, fmt.Errorf(\"decode poll response: %w\", err)\n\t}\n\tif pollResp.Code != 0 {\n\t\treturn nil, fmt.Errorf(\"poll error code=%d msg=%s\", pollResp.Code, pollResp.Msg)\n\t}\n\n\tif len(pollResp.Data.ExtractResult) == 0 {\n\t\treturn nil, nil\n\t}\n\n\t// Dump the raw extract_result JSON for debugging\n\trawExtract := string(pollResp.Data.ExtractResult)\n\tif len(rawExtract) > 4000 {\n\t\tlogger.Infof(context.Background(), \"[MinerUCloud] Raw extract_result (truncated to 4000 chars): %s ...\", rawExtract[:4000])\n\t} else {\n\t\tlogger.Infof(context.Background(), \"[MinerUCloud] Raw extract_result: %s\", rawExtract)\n\t}\n\n\t// Pretty-print the structure to reveal all available fields","sourceCodeStart":270,"sourceCodeEnd":306,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/infrastructure/docparser/mineru_cloud_converter.go#L270-L306","documentation":"This error means the response body read from the MinerU Cloud batch-status poll endpoint is not valid JSON; json.Unmarshal failed inside fetchBatchStatus (mineru_cloud_converter.go:288). The library expects a batchPollResponse object with code/msg/data fields, so anything else (HTML error page, empty body, truncated JSON) triggers it. The decode error is wrapped so the JSON syntax error message is preserved.","triggerScenarios":"fetchBatchStatus (via pollBatchResult) receives a 200 (or otherwise accepted) response whose body is not the expected JSON shape: an HTML login/error page from a misconfigured gateway, an empty body, or truncated JSON from a partial read.","commonSituations":"Base URL misconfigured to point at a proxy or wrong host that returns HTML; captive portal or auth gateway intercepting the request; MinerU Cloud API version change altering the response contract; body truncated by proxy that also broke decoding.","solutions":["Log respBody (or a prefix of it) on this error to see what was actually returned — it usually reveals HTML or an error page.","Verify the MinerU Cloud API base URL and that no proxy intercepts the endpoint.","Confirm the API version/contract: batchPollResponse expects {\"code\":0,\"msg\":...,\"data\":{\"extract_result\":...}}.","Retry transient cases; if consistently failing, the endpoint or auth is wrong rather than transient."],"exampleFix":"// before\nif err := json.Unmarshal(respBody, &pollResp); err != nil {\n    return nil, fmt.Errorf(\"decode poll response: %w\", err)\n}\n// after\nif err := json.Unmarshal(respBody, &pollResp); err != nil {\n    return nil, fmt.Errorf(\"decode poll response: %w (body: %.200s)\", err, string(respBody))\n}","handlingStrategy":"validation","validationCode":"ct := resp.Header.Get(\"Content-Type\")\nif !strings.Contains(ct, \"application/json\") {\n    return fmt.Errorf(\"unexpected poll response content-type: %s\", ct)\n}","typeGuard":"func isValidPollResponse(b []byte) bool {\n    var probe struct {\n        Code int `json:\"code\"`\n        Data struct{} `json:\"data\"`\n    }\n    return json.Unmarshal(b, &probe) == nil\n}","tryCatchPattern":"items, err := pollBatchResult(ctx, batchID)\nif err != nil {\n    if strings.Contains(err.Error(), \"decode poll response\") {\n        // log raw body via wrapped context; treat as endpoint/contract misconfig\n        log.Printf(\"MinerU poll returned non-JSON: %v\", err)\n    }\n    return err\n}","preventionTips":["Check Content-Type is application/json before unmarshaling.","Verify the MinerU Cloud base URL is not behind an auth gateway or captive portal.","Log a body prefix on decode failure to spot HTML error pages immediately."],"tags":["json","decoding","http","go","api-contract"],"backgroundTag":"json-decode-error","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}