Tencent/WeKnora · error
decode poll response
Error message
decode poll response: %w
What it means
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.
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.
Example fix
// before
if err := json.Unmarshal(respBody, &pollResp); err != nil {
return nil, fmt.Errorf("decode poll response: %w", err)
}
// after
if err := json.Unmarshal(respBody, &pollResp); err != nil {
return nil, fmt.Errorf("decode poll response: %w (body: %.200s)", err, string(respBody))
} Defensive patterns
Strategy: validation
Validate before calling
ct := resp.Header.Get("Content-Type")
if !strings.Contains(ct, "application/json") {
return fmt.Errorf("unexpected poll response content-type: %s", ct)
} Type guard
func isValidPollResponse(b []byte) bool {
var probe struct {
Code int `json:"code"`
Data struct{} `json:"data"`
}
return json.Unmarshal(b, &probe) == nil
} Try / catch
items, err := pollBatchResult(ctx, batchID)
if err != nil {
if strings.Contains(err.Error(), "decode poll response") {
// log raw body via wrapped context; treat as endpoint/contract misconfig
log.Printf("MinerU poll returned non-JSON: %v", err)
}
return err
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- decode extract_result array
- decode extract_result object
- failed to decode API response
- http decode read response
- bing API returned status
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/543c294a8a6c9002.
Report an issue: GitHub.
Appendix: source
Thrown at internal/infrastructure/docparser/mineru_cloud_converter.go:288
for k, v := range headers {
httpReq.Header.Set(k, v)
}
client := utils.NewSSRFSafeHTTPClient(utils.SSRFSafeHTTPClientConfig{Timeout: 30 * time.Second, MaxRedirects: 5})
resp, err := client.Do(httpReq)
if err != nil {
return nil, err
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("read poll response body: %w", err)
}
var pollResp batchPollResponse
if err := json.Unmarshal(respBody, &pollResp); err != nil {
return nil, fmt.Errorf("decode poll response: %w", err)
}
if pollResp.Code != 0 {
return nil, fmt.Errorf("poll error code=%d msg=%s", pollResp.Code, pollResp.Msg)
}
if len(pollResp.Data.ExtractResult) == 0 {
return nil, nil
}
// Dump the raw extract_result JSON for debugging
rawExtract := string(pollResp.Data.ExtractResult)
if len(rawExtract) > 4000 {
logger.Infof(context.Background(), "[MinerUCloud] Raw extract_result (truncated to 4000 chars): %s ...", rawExtract[:4000])
} else {
logger.Infof(context.Background(), "[MinerUCloud] Raw extract_result: %s", rawExtract)
}
// Pretty-print the structure to reveal all available fieldsView on GitHub (pinned to 988cbb0330)