Tencent/WeKnora · error

read poll response body: %w

Error message

read poll response body: %w

What it means

This error wraps a failure to read the HTTP response body while polling the MinerU Cloud batch status endpoint in fetchBatchStatus (internal/infrastructure/docparser/mineru_cloud_converter.go:283). After the HTTP request succeeds, io.ReadAll(resp.Body) can still fail if the connection is reset, times out mid-body, or the server closes the stream early. The library surfaces the underlying io error wrapped with %w so the root cause (e.g. unexpected EOF, connection reset) is preserved.

Source

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

	url := fmt.Sprintf("%s/extract-results/batch/%s", c.baseURL, batchID)
	httpReq, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
	if err != nil {
		return nil, err
	}
	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])

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Retry the poll request: fetchBatchStatus is called repeatedly by pollBatchResult, so a transient read failure usually resolves on the next poll interval.
  2. Check network path stability (proxy/firewall) between the host and the MinerU Cloud API endpoint.
  3. Inspect the wrapped error (errors.Unwrap / %v of the cause) to confirm whether it is 'unexpected EOF', 'connection reset by peer', or a client timeout, and tune the HTTP client timeout accordingly.
  4. If it persists, verify the MinerU Cloud service status or endpoint URL configuration.

Example fix

// before
client := &http.Client{Timeout: 10 * time.Second}
// after
// increase timeout / add retry in the polling loop
client := &http.Client{Timeout: 60 * time.Second}
// in pollBatchResult:
// for attempt := 0; attempt < 3; attempt++ {
//     resp, err := fetchBatchStatus(ctx, id)
//     if err == nil { break }
//     time.Sleep(pollInterval)
// }
Defensive patterns

Strategy: retry

Validate before calling

if resp.Body == nil {
    return errors.New("poll response has no body")
}
if resp.ContentLength == 0 {
    return errors.New("poll response body is empty")
}

Try / catch

items, err := pollBatchResult(ctx, batchID)
if err != nil {
    var netErr net.Error
    if errors.As(err, &netErr) || errors.Is(err, io.ErrUnexpectedEOF) {
        // transient: retry the poll after the interval
        time.Sleep(pollInterval)
        return pollBatchResult(ctx, batchID)
    }
    return fmt.Errorf("poll failed permanently: %w", err)
}

Prevention

When it happens

Trigger: Calling pollBatchResult -> fetchBatchStatus when the MinerU Cloud server accepts the request headers but the TCP stream breaks before the full JSON body arrives: network interruption, proxy/LB idle timeout, server crash mid-response, or response body truncated by a Content-Length mismatch.

Common situations: Long-running batch polls over flaky VPN or corporate proxies that kill idle/long responses; container DNS or NAT timeouts dropping keep-alive connections; MinerU Cloud returning a very large poll response that gets cut off on slow links.

Related errors


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