Tencent/WeKnora · error

create form file: %w

Error message

create form file: %w

What it means

callFileParse builds a multipart/form-data request and writer.CreateFormFile('files', uploadFileName) failed. This is nearly impossible in practice (CreateFormFile only errors if the form was already closed or the field name/filename contain invalid characters), but it indicates the multipart writer is in a bad state.

Source

Thrown at internal/infrastructure/docparser/mineru_converter.go:229

		"return_model_output": "false",
		"return_content_list": "true",
	}
	if c.language != "" {
		fields["lang_list"] = c.language
	}
	if c.vlmServerURL != "" && (strings.HasPrefix(c.backend, "vlm-http-client") || strings.HasPrefix(c.backend, "hybrid-http-client")) {
		fields["server_url"] = c.vlmServerURL
	}
	for k, v := range fields {
		_ = writer.WriteField(k, v)
	}

	uploadFileName := minerUUploadFileName(fileName, fileType)

	// File part
	part, err := writer.CreateFormFile("files", uploadFileName)
	if err != nil {
		return "", nil, fmt.Errorf("create form file: %w", err)
	}
	if _, err := part.Write(content); err != nil {
		return "", nil, fmt.Errorf("write file content: %w", err)
	}
	writer.Close()

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

	client := utils.NewSSRFSafeHTTPClient(utils.SSRFSafeHTTPClientConfig{
		Timeout:      mineruTimeout,
		MaxRedirects: 5,
	})
	resp, err := client.Do(httpReq)
	if err != nil {

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Sanitize minerUUploadFileName output: strip CR/LF, control chars, and quotes from the filename derived from req.FileName.
  2. Verify CreateFormFile is called before writer.Close() and exactly once.
  3. Log the computed uploadFileName to spot malformed input filenames.
  4. This is effectively a programming/invariant bug — if it reproduces, add a unit test with hostile filenames.

Example fix

// before
uploadFileName := minerUUploadFileName(fileName, fileType)
// after
uploadFileName = strings.Map(func(r rune) rune {
    if r == '\r' || r == '\n' || r == '"' || unicode.IsControl(r) {
        return '_'
    }
    return r
}, minerUUploadFileName(fileName, fileType))
Defensive patterns

Strategy: validation

Validate before calling

func safeUploadName(name string) string {
    return strings.Map(func(r rune) rune {
        if r == '\r' || r == '\n' || r == '"' || unicode.IsControl(r) {
            return '_'
        }
        return r
    }, name)
}

Type guard

func isHeaderSafeName(name string) bool {
    return name != "" && !strings.ContainsAny(name, "\r\n\"\x00")
}

Try / catch

if err != nil && strings.Contains(err.Error(), "create form file") {
    // invariant violation: sanitize filename and retry once
    return sanitizeAndRetry(req)
}

Prevention

When it happens

Trigger: writer.CreateFormFile returns an error after writer.Close() was already called, or if uploadFileName contains invalid header characters (newlines, quotes breaking the Content-Disposition header).

Common situations: uploadFileName derived from req.FileName carries control characters, CR/LF injection, or pathological quotes; a refactor closed the writer before creating all parts.

Related errors


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