Tencent/WeKnora · error

decode poll response: %w

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.

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 fields

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Log respBody (or a prefix of it) on this error to see what was actually returned — it usually reveals HTML or an error page.
  2. Verify the MinerU Cloud API base URL and that no proxy intercepts the endpoint.
  3. Confirm the API version/contract: batchPollResponse expects {"code":0,"msg":...,"data":{"extract_result":...}}.
  4. 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

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


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