Tencent/WeKnora · error

write file content

Error message

write file content: %w

What it means

Immediately after creating the 'file' part, submitJob writes the whole document bytes into it via part.Write(content). If that write fails — practically only when the underlying buffer/connection errors or memory is exhausted — the error is wrapped as 'write file content'. The multipart request could not be assembled with the document payload.

Solutions

  1. Check the wrapped cause for the underlying io error
  2. For large files, stream content to a temp file and use os.Open as the request body instead of buffering fully in memory
  3. Ensure part.Write occurs before writer.Close()
  4. Retest with a smaller document to isolate size-related memory pressure

Example fix

// before
var body bytes.Buffer
writer := multipart.NewWriter(&body) // large file -> memory pressure
// after
f, _ := os.CreateTemp("", "paddleocr-*")
writer := multipart.NewWriter(f) // stream to disk-backed buffer
Defensive patterns

Strategy: validation

Validate before calling

if len(content) > 100<<20 { // 100 MB
    return fmt.Errorf("document too large for in-memory upload: %d bytes", len(content))
}

Type guard

func isPartWriteError(err error) bool {
    return err != nil && strings.Contains(err.Error(), "write file content")
}

Try / catch

out, err := reader.Read(ctx, req)
if isPartWriteError(err) {
    if errors.Is(err, ErrWriterClosed) { return fmt.Errorf("ordering bug: write after close") }
    return fmt.Errorf("upload payload write failed (consider streaming): %w", err)
}

Prevention

When it happens

Trigger: Read -> submitJob -> part.Write(content) returns an error on a large content payload; effectively indicates an io.Writer failure on the multipart part's underlying writer (bytes.Buffer allocation failure) or an already-closed/errored writer.

Common situations: Uploading very large documents causing the in-memory bytes.Buffer to exhaust memory; writer closed prematurely after a refactor; content slice referencing unavailable data (rare).

Related errors


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

Appendix: source

Thrown at internal/infrastructure/docparser/paddleocr_vl_cloud_converter.go:134

	fileName := req.FileName
	if fileName == "" {
		ext := strings.TrimPrefix(req.FileType, ".")
		if ext == "" {
			ext = "pdf"
		}
		fileName = "document." + ext
	}

	var body bytes.Buffer
	writer := multipart.NewWriter(&body)
	_ = writer.WriteField("model", c.model)
	_ = writer.WriteField("optionalPayload", string(optional))
	part, err := writer.CreateFormFile("file", filepath.Base(fileName))
	if err != nil {
		return "", fmt.Errorf("create form file: %w", err)
	}
	if _, err := part.Write(content); err != nil {
		return "", fmt.Errorf("write file content: %w", err)
	}
	writer.Close()

	httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL, &body)
	if err != nil {
		return "", fmt.Errorf("create request: %w", err)
	}
	httpReq.Header.Set("Authorization", "bearer "+c.token)
	httpReq.Header.Set("Content-Type", writer.FormDataContentType())

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

	respBody, _ := io.ReadAll(resp.Body)

View on GitHub (pinned to 988cbb0330)