Tencent/WeKnora · warning

marshal payload: %w

Error message

marshal payload: %w

What it means

applyUploadURLs marshals the batch request payload (filename, extension, table/language options) to JSON before POSTing it; a json.Marshal failure is wrapped as "marshal payload: %w". With a plain map of strings/bools this is nearly impossible at runtime, but the library defends the error path anyway.

Source

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

func (c *MinerUCloudReader) applyUploadURLs(ctx context.Context, fileName, ext string) (string, string, error) {
	modelVersion := c.model
	if strings.ToLower(ext) == ".html" {
		modelVersion = "MinerU-HTML"
	}

	payload := map[string]interface{}{
		"files":          []map[string]string{{"name": fileName, "data_id": uuid.New().String()}},
		"model_version":  modelVersion,
		"is_ocr":         c.ocrEnable,
		"enable_formula": c.formulaEnable,
		"enable_table":   c.tableEnable,
		"language":       c.language,
	}

	body, err := json.Marshal(payload)
	if err != nil {
		return "", "", fmt.Errorf("marshal payload: %w", err)
	}

	httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL+"/file-urls/batch", bytes.NewReader(body))
	if err != nil {
		return "", "", fmt.Errorf("create request: %w", err)
	}
	httpReq.Header.Set("Authorization", "Bearer "+c.apiKey)
	httpReq.Header.Set("Content-Type", "application/json")

	client := utils.NewSSRFSafeHTTPClient(utils.SSRFSafeHTTPClientConfig{Timeout: 30 * time.Second, MaxRedirects: 5})
	resp, err := client.Do(httpReq)
	if err != nil {
		return "", "", fmt.Errorf("HTTP request: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		respBody, _ := io.ReadAll(resp.Body)

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Inspect the wrapped cause to identify which payload field failed to serialize.
  2. Check how the converter's options (tableEnable, language, etc.) are populated; ensure only JSON-compatible types (string, bool, number) are set.
  3. Fix the configuration wiring so no func/channel/unsupported type reaches the payload.
  4. If caused by a library bug, report/patch — normally this path cannot fail with standard inputs.

Example fix

// before: non-serializable value in payload options
c.language = func() string { return "en" } // json.Marshal fails
// after
if l, ok := langOption.(string); ok { c.language = l } else { c.language = "en" }
Defensive patterns

Strategy: validation

Validate before calling

payload := map[string]interface{}{"enable_table": tableEnable, "language": language}
if _, err := json.Marshal(payload); err != nil {
    return fmt.Errorf("converter options are not JSON-serializable: %w", err)
}

Type guard

func jsonSerializable(v interface{}) bool {
    b, err := json.Marshal(v)
    return err == nil && b != nil
}

Try / catch

res, err := converter.Read(ctx, req)
if err != nil {
    if strings.Contains(err.Error(), "marshal payload") {
        return fmt.Errorf("mineru converter options contain a non-serializable value: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Read -> applyUploadURLs where json.Marshal of the payload map returns an error — practically only if a payload value becomes a non-JSON-serializable type (channel, func, or unsupported custom type) via configuration.

Common situations: Custom configuration wiring injecting a non-serializable value (e.g. a func or channel) into the converter's option fields; misuse of the struct by embedding unsupported types; essentially never triggered by standard string/bool config.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


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