{"record":{"id":"437e25a7eb144770","repo":"Tencent/WeKnora","slug":"create-form-file-w-437e25","errorCode":null,"errorMessage":"create form file: %w","messagePattern":"create form file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/infrastructure/docparser/paddleocr_vl_cloud_converter.go","lineNumber":131,"sourceCode":"\t\treturn \"\", fmt.Errorf(\"marshal optionalPayload: %w\", err)\n\t}\n\n\tfileName := req.FileName\n\tif fileName == \"\" {\n\t\text := strings.TrimPrefix(req.FileType, \".\")\n\t\tif ext == \"\" {\n\t\t\text = \"pdf\"\n\t\t}\n\t\tfileName = \"document.\" + ext\n\t}\n\n\tvar body bytes.Buffer\n\twriter := multipart.NewWriter(&body)\n\t_ = writer.WriteField(\"model\", c.model)\n\t_ = writer.WriteField(\"optionalPayload\", string(optional))\n\tpart, err := writer.CreateFormFile(\"file\", filepath.Base(fileName))\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"create form file: %w\", err)\n\t}\n\tif _, err := part.Write(content); err != nil {\n\t\treturn \"\", fmt.Errorf(\"write file content: %w\", err)\n\t}\n\twriter.Close()\n\n\thttpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, c.baseURL, &body)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"create request: %w\", err)\n\t}\n\thttpReq.Header.Set(\"Authorization\", \"bearer \"+c.token)\n\thttpReq.Header.Set(\"Content-Type\", writer.FormDataContentType())\n\n\tclient := utils.NewSSRFSafeHTTPClient(utils.SSRFSafeHTTPClientConfig{Timeout: 60 * time.Second, MaxRedirects: 5})\n\tresp, err := client.Do(httpReq)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"HTTP request: %w\", err)\n\t}","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/infrastructure/docparser/paddleocr_vl_cloud_converter.go#L113-L149","documentation":"submitJob builds a multipart/form-data body and calls writer.CreateFormFile(\"file\", filepath.Base(fileName)) to attach the uploaded document. This fails only when the multipart writer has already been closed or suffered an internal error, meaning the form body is in an invalid state. The file part could not be created, so the upload cannot proceed.","triggerScenarios":"Read -> submitJob -> CreateFormFile returns an error — occurs when writer.Close() was called before CreateFormFile, or the multipart writer is otherwise in an error state (e.g. a prior WriteField write already poisoned it after an underlying io error on the buffer).","commonSituations":"Code refactors that reordered Close() before CreateFormFile; a bytes.Buffer write failure (virtually only under memory exhaustion); duplicating a part with the same field name after Close.","solutions":["Verify field writes and CreateFormFile all happen before writer.Close()","Check the wrapped error for the underlying writer state problem","Ensure CreateFormFile is called exactly once per upload with a valid, non-empty filename from filepath.Base","If triggered by OOM pressure on the buffer, stream to a temp file instead of an in-memory bytes.Buffer for very large documents"],"exampleFix":"// before\nwriter.Close()\npart, err := writer.CreateFormFile(\"file\", name) // fails: writer closed\n// after\npart, err := writer.CreateFormFile(\"file\", name)\nif _, err := part.Write(content); err != nil { ... }\nwriter.Close()","handlingStrategy":"try-catch","validationCode":"if fileName == \"\" { return errors.New(\"file name required for multipart upload\") }\nif err == nil && writerClosed { return errors.New(\"multipart writer closed before file part created\") }","typeGuard":"func isFormFileError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"create form file\")\n}","tryCatchPattern":"out, err := reader.Read(ctx, req)\nif isFormFileError(err) {\n    return fmt.Errorf(\"multipart assembly bug (check write/close ordering): %w\", err)\n}","preventionTips":["Always create all parts before calling writer.Close()","Call CreateFormFile exactly once per upload","Use filepath.Base to sanitize user-supplied file names","Add a regression test covering the full multipart build for each Read path"],"tags":["multipart","upload","paddleocr","docparser"],"backgroundTag":"multipart-form-error","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}