{"record":{"id":"3b5a4d0ecd512e2a","repo":"valyala/fasthttp","slug":"cannot-close-form-file-q-q-w","errorCode":null,"errorMessage":"cannot close form file %q (%q): %w","messagePattern":"cannot close form file %q \\(%q\\): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"http.go","lineNumber":1258,"sourceCode":"\t}\n\n\t// marshal files\n\tfor k, fvv := range f.File {\n\t\tfor _, fv := range fvv {\n\t\t\tvw, err := mw.CreatePart(fv.Header)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"cannot create form file %q (%q): %w\", k, fv.Filename, err)\n\t\t\t}\n\t\t\tfh, err := fv.Open()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"cannot open form file %q (%q): %w\", k, fv.Filename, err)\n\t\t\t}\n\t\t\tif _, err = copyZeroAlloc(vw, fh); err != nil {\n\t\t\t\t_ = fh.Close()\n\t\t\t\treturn fmt.Errorf(\"error when copying form file %q (%q): %w\", k, fv.Filename, err)\n\t\t\t}\n\t\t\tif err = fh.Close(); err != nil {\n\t\t\t\treturn fmt.Errorf(\"cannot close form file %q (%q): %w\", k, fv.Filename, err)\n\t\t\t}\n\t\t}\n\t}\n\n\tif err := mw.Close(); err != nil {\n\t\treturn fmt.Errorf(\"error when closing multipart form writer: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc readMultipartForm(r io.Reader, boundary string, size, maxInMemoryFileSize int) (*multipart.Form, error) {\n\t// Do not care about memory allocations here, since they are tiny\n\t// compared to multipart data (aka multi-MB files) usually sent\n\t// in multipart/form-data requests.\n\n\tif size <= 0 {\n\t\treturn nil, fmt.Errorf(\"form size must be greater than 0: given %d\", size)","sourceCodeStart":1240,"sourceCodeEnd":1276,"githubUrl":"https://github.com/valyala/fasthttp/blob/c96f600972c6f4a7a30d664257b340ebe9d60124/http.go#L1240-L1276","documentation":"fasthttp wraps the error returned by closing the multipart part file handle after copying its contents into a multipart/form-data body. Close can fail especially for files written via os.File (flush/sync failures) or custom closers.","triggerScenarios":"After a successful copyZeroAlloc, fv.Open()'s handle's Close() returns a non-nil error while writing a request with form file fields (SetFormFile / SetFormFileContent with a Closer that errors).","commonSituations":"Custom io.ReadCloser implementations whose Close reports a deferred write error; tmpfile-based uploads where the underlying descriptor was already closed by user code; network-backed readers whose Close does a final flush that fails.","solutions":["Inspect the wrapped cause; most Close errors indicate a resource issue with the underlying reader.","Do not double-close the handle you passed to fasthttp before the request completes.","Fix the custom ReadCloser's Close implementation to be idempotent and error-free.","Use SetFormFileContent with a plain byte slice if streaming close semantics are not needed."],"exampleFix":"// before\ntype rc struct{ io.Reader }\nfunc (r rc) Close() error { return errors.New(\"flush failed\") }\nreq.SetFormFileContent(\"f\", rc{bytes.NewReader(data)}, \"a.txt\")\n// after\nreq.SetFormFileContent(\"f\", data, \"a.txt\") // bytes avoid Close paths","handlingStrategy":"validation","validationCode":null,"typeGuard":"func safeCloser(c io.ReadCloser) io.ReadCloser {\n    return idempotentCloser{c}\n}\ntype idempotentCloser struct{ io.ReadCloser }\nfunc (i idempotentCloser) Close() error {\n    err := i.ReadCloser.Close()\n    i.ReadCloser = nopCloser{}\n    return err\n}","tryCatchPattern":"if err := client.Do(req, resp); err != nil {\n    if strings.Contains(err.Error(), \"cannot close form file\") {\n        log.Printf(\"form file close failed (upload likely still sent): %v\", err)\n    }\n    return err\n}","preventionTips":["Make custom ReadClosers idempotent and error-free on Close","Prefer byte-slice bodies (SetFormFileContent) when streaming isn't required","Never double-close handles handed to the library"],"tags":["multipart","resource-cleanup","io"],"backgroundTag":"issue-close-failed","analyzedSha":"c96f600972c6f4a7a30d664257b340ebe9d60124","analyzedAt":"2026-08-31T22:48:28.265Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}