valyala/fasthttp · error
cannot close form file %q (%q): %w
Error message
cannot close form file %q (%q): %w
What it means
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.
Source
Thrown at http.go:1258
}
// marshal files
for k, fvv := range f.File {
for _, fv := range fvv {
vw, err := mw.CreatePart(fv.Header)
if err != nil {
return fmt.Errorf("cannot create form file %q (%q): %w", k, fv.Filename, err)
}
fh, err := fv.Open()
if err != nil {
return fmt.Errorf("cannot open form file %q (%q): %w", k, fv.Filename, err)
}
if _, err = copyZeroAlloc(vw, fh); err != nil {
_ = fh.Close()
return fmt.Errorf("error when copying form file %q (%q): %w", k, fv.Filename, err)
}
if err = fh.Close(); err != nil {
return fmt.Errorf("cannot close form file %q (%q): %w", k, fv.Filename, err)
}
}
}
if err := mw.Close(); err != nil {
return fmt.Errorf("error when closing multipart form writer: %w", err)
}
return nil
}
func readMultipartForm(r io.Reader, boundary string, size, maxInMemoryFileSize int) (*multipart.Form, error) {
// Do not care about memory allocations here, since they are tiny
// compared to multipart data (aka multi-MB files) usually sent
// in multipart/form-data requests.
if size <= 0 {
return nil, fmt.Errorf("form size must be greater than 0: given %d", size)View on GitHub (pinned to c96f600972)
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.
Example fix
// before
type rc struct{ io.Reader }
func (r rc) Close() error { return errors.New("flush failed") }
req.SetFormFileContent("f", rc{bytes.NewReader(data)}, "a.txt")
// after
req.SetFormFileContent("f", data, "a.txt") // bytes avoid Close paths Defensive patterns
Strategy: validation
Type guard
func safeCloser(c io.ReadCloser) io.ReadCloser {
return idempotentCloser{c}
}
type idempotentCloser struct{ io.ReadCloser }
func (i idempotentCloser) Close() error {
err := i.ReadCloser.Close()
i.ReadCloser = nopCloser{}
return err
} Try / catch
if err := client.Do(req, resp); err != nil {
if strings.Contains(err.Error(), "cannot close form file") {
log.Printf("form file close failed (upload likely still sent): %v", err)
}
return err
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- error when copying form file %q (%q): %w
- fasthttp: request content-type has bad boundary or is not mu
- form boundary cannot be empty
- fasthttp: there is no uploaded file associated with the give
- cannot open already opened file: %w
AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31).
Data as JSON: /api/errors/3b5a4d0ecd512e2a.
Report an issue: GitHub.