{"record":{"id":"3bd5fe16f620c1b8","repo":"openfaas/faas","slug":"a-body-is-required-for-this-endpoint","errorCode":null,"errorMessage":"A body is required for this endpoint","messagePattern":"A body is required for this endpoint","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"gateway/handlers/alerthandler.go","lineNumber":26,"sourceCode":"import (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"math\"\n\t\"net/http\"\n\n\t\"github.com/openfaas/faas/gateway/pkg/middleware\"\n\t\"github.com/openfaas/faas/gateway/requests\"\n\t\"github.com/openfaas/faas/gateway/scaling\"\n)\n\n// MakeAlertHandler handles alerts from Prometheus Alertmanager\nfunc MakeAlertHandler(service scaling.ServiceQuery, defaultNamespace string) http.HandlerFunc {\n\treturn func(w http.ResponseWriter, r *http.Request) {\n\n\t\tif r.Body == nil {\n\t\t\thttp.Error(w, \"A body is required for this endpoint\", http.StatusBadRequest)\n\t\t\treturn\n\t\t}\n\n\t\tdefer r.Body.Close()\n\n\t\tbody, err := io.ReadAll(r.Body)\n\t\tif err != nil {\n\t\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t\tw.Write([]byte(\"Unable to read alert.\"))\n\n\t\t\tlog.Println(err)\n\t\t\treturn\n\t\t}\n\n\t\tvar req requests.PrometheusAlert\n\t\tif err := json.Unmarshal(body, &req); err != nil {\n\t\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t\tw.Write([]byte(\"Unable to parse alert, bad format.\"))","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/openfaas/faas/blob/8d803bf9e2655aec6a60fd0e25b392839f96af95/gateway/handlers/alerthandler.go#L8-L44","documentation":"MakeAlertHandler serves POST /system/alert, the webhook endpoint Prometheus Alertmanager calls so the gateway can scale functions from zero. The handler rejects any request whose r.Body is nil with 400 Bad Request before parsing the alert JSON. Go's net/http server always supplies a non-nil body for real requests, so this branch is a defensive guard: an empty body passes it and fails later at JSON decoding.","triggerScenarios":"Invoking POST /system/alert with no payload at all, e.g. curl -X POST http://gateway:8080/system/alert without a -d flag; unit tests that pass a bare &http.Request{} with a nil Body directly to the handler.","commonSituations":"Manually probing the endpoint to verify Alertmanager wiring and forgetting the payload; custom health checks that POST without a body; hand-rolled scripts forwarding alerts without copying the request body.","solutions":["Send a JSON alert payload: curl -X POST -H 'Content-Type: application/json' -d '{\"status\":\"firing\",\"alerts\":[]}' http://gateway:8080/system/alert","Verify the Alertmanager receiver URL points at the gateway's /system/alert path","Make sure no proxy in front of the gateway strips request bodies","In Go tests, build requests with http.NewRequest and a bytes.Reader body"],"exampleFix":"# before\ncurl -X POST http://gateway:8080/system/alert\n\n# after\ncurl -X POST -H 'Content-Type: application/json' \\\n  -d '{\"status\":\"firing\",\"alerts\":[]}' \\\n  http://gateway:8080/system/alert","handlingStrategy":"validation","validationCode":"// client-side: never call /system/alert without a payload\nif len(alertPayload) == 0 {\n    return errors.New(\"alert payload is required\")\n}\nreq, _ := http.NewRequest(http.MethodPost, gatewayURL+\"/system/alert\", bytes.NewReader(alertPayload))","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Test Alertmanager receivers with amtool or curl including a real JSON body","Add a smoke test that POSTs a minimal firing alert and expects 200","Never probe the endpoint with an empty body"],"tags":["http","webhook","alertmanager","autoscaling","go"],"backgroundTag":null,"analyzedSha":"8d803bf9e2655aec6a60fd0e25b392839f96af95","analyzedAt":"2026-08-16T00:12:29.759Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}