Go version

go1.24.6

Output of go env in your module/workspace:

GOVERSION="go1.24.6"

What did you do?

Run the following code

package main

import (
    "fmt"
    "net/http"

    "net/http/httptest"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Printf("r.Body: %#v\n", r.Body)
    err := r.ParseMultipartForm(1024)
    if err != nil {
        fmt.Println("r.ParseMultipartForm error:", err)
        w.WriteHeader(500)
    }
}

func main() {
    req := httptest.NewRequest(http.MethodPost, "http://localhost/upload", nil)
    req.Header.Set("Content-Type", "multipart/form-data;boundary=-----TEST")
    fmt.Printf("req.Body: %#v\n", req.Body)
    w := httptest.NewRecorder()
    handler(w, req)
    resp := w.Result()
    fmt.Println("response code:", resp.StatusCode)
}

I created a http POST form request without body

What did you see happen?

req.Body: http.noBody{} r.Body: http.noBody{} r.ParseMultipartForm error: multipart: NextPart: EOF response code: 500

What did you expect to see?

req.Body: http.noBody{} r.Body: http.noBody{} r.ParseMultipartForm error: missing form body response code: 500

Comment From: gopherbot

Change https://go.dev/cl/692756 mentions this issue: net/http: fix server-side http parse form error inaccurate issue

Comment From: dmitshur

CC @neild.

Comment From: neild

The "missing form body" error was added in https://go.dev/cl/384454 to handle the case where Request.Body is nil without panicking.

For server requests, Request.Body is never nil, even for zero-length requests.

There are a variety of ways in which a multipart form can fail to parse, and I don't think it makes sense to special-case the one being demonstrated here. (Basically, a request with a Content-Length: 0 header where the request size is known to be zero bytes after parsing the headers.) Perhaps we should have a better error for truncated or zero-length multipart form bodies, but if so it should be consistent regardless of how the body is transferred. That is, sending a zero-length body with a Content-Length: 0 header vs. with Transfer-Encoding: chunked should not produce different errors.