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
- Sanitize minerUUploadFileName output: strip CR/LF, control chars, and quotes from the filename derived from req.FileName.
- Verify CreateFormFile is called before writer.Close() and exactly once.
- Log the computed uploadFileName to spot malformed input filenames.
- 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
- Sanitize user-supplied filenames before building multipart forms
- Unit-test request building with hostile filenames (CR/LF, quotes, unicode)
- Never call writer.Close() before all parts are created
- Fuzz the filename-derivation function
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
- write file content: %w
- member_limit must be >= 0
- missing query parameter
- no queries provided
- missing id parameter
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/552e5f77a0d0faa3.
Report an issue: GitHub.