valyala/fasthttp · error

form size must be greater than 0: given %d

Error message

form size must be greater than 0: given %d

What it means

fasthttp validates the declared Content-Length (size) before parsing an incoming multipart/form-data body in readMultipartForm; a non-positive size cannot yield any body. This is a server-side guard so it never passes a useless LimitReader to multipart.Reader.

Source

Thrown at http.go:1276

				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)
	}
	lr := io.LimitReader(r, int64(size))
	mr := multipart.NewReader(lr, boundary)
	f, err := mr.ReadForm(int64(maxInMemoryFileSize))
	if err != nil {
		return nil, fmt.Errorf("cannot read multipart/form-data body: %w", err)
	}
	return f, nil
}

// Reset clears request contents.
func (req *Request) Reset() {
	req.userValues.Reset() // it should be at the top, since some values might implement io.Closer interface
	if bodyPoolSizeLimit := int(atomic.LoadInt64(&requestBodyPoolSizeLimit)); bodyPoolSizeLimit >= 0 && req.body != nil {
		req.ReleaseBody(bodyPoolSizeLimit)
	}
	req.Header.Reset()
	req.resetSkipHeader()

View on GitHub (pinned to c96f600972)

Solutions

  1. Fix the client to send a correct Content-Length with the multipart body.
  2. Server-side: reject requests without a body before calling ctx.FormFile/MultipartForm.
  3. If behind a proxy, configure it to preserve Content-Length for multipart posts.
  4. Send the multipart request via fasthttp's Request (which sets Content-Length automatically) instead of hand-rolled writers.

Example fix

// before (client)
req.Header.SetMethod("POST")
req.Header.Set("Content-Type", "multipart/form-data; boundary=x")
// body written without length
// after
req.SetFormFileContent("file", data, "a.txt") // fasthttp sets CL + boundary
client.Do(req, resp)
Defensive patterns

Strategy: validation

Validate before calling

if ctx.Request.Header.ContentLength() <= 0 {
    ctx.Error("multipart body required", fasthttp.StatusBadRequest)
    return
}

Type guard

func hasMultipartBody(ctx *fasthttp.RequestCtx) bool {
    return ctx.Request.Header.ContentLength() > 0 &&
        strings.HasPrefix(ctx.Request.Header.ContentType(), "multipart/form-data")
}

Try / catch

form, err := ctx.MultipartForm()
if err != nil {
    if strings.Contains(err.Error(), "form size must be greater than 0") {
        ctx.Error("empty multipart body", fasthttp.StatusBadRequest)
        return
    }
    return err
}

Prevention

When it happens

Trigger: Server request handling (ctx.FormFile / MultipartForm) on a request whose declared multipart size is <= 0 — e.g. Content-Length missing or 0 while a multipart Content-Type is present.

Common situations: Clients sending multipart bodies with chunked encoding or no Content-Length; proxies stripping Content-Length; load-generator clients that post empty multipart bodies.

Related errors


AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31). Data as JSON: /api/errors/06022721dca270c3. Report an issue: GitHub.