Tencent/WeKnora · error

write file content: %w

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.

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)

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.