{"record":{"id":"8c95e0b54977ace1","repo":"hashicorp/nomad","slug":"request-body-is-empty","errorCode":null,"errorMessage":"Request body is empty","messagePattern":"Request body is empty","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"command/agent/http.go","lineNumber":912,"sourceCode":"\t\t}\n\t\t// write response\n\t\tif obj != nil {\n\t\t\tresp.Write(obj)\n\t\t}\n\t}\n\treturn f\n}\n\n// isAPIClientError returns true if the passed http code represents a client error\nfunc isAPIClientError(code int) bool {\n\treturn 400 <= code && code <= 499\n}\n\n// decodeBody is used to decode a JSON request body\nfunc decodeBody(req *http.Request, out any) error {\n\n\tif req.Body == http.NoBody {\n\t\treturn errors.New(\"Request body is empty\")\n\t}\n\n\tdec := json.NewDecoder(req.Body)\n\treturn dec.Decode(&out)\n}\n\n// setIndex is used to set the index response header\nfunc setIndex(resp http.ResponseWriter, index uint64) {\n\tresp.Header().Set(\"X-Nomad-Index\", strconv.FormatUint(index, 10))\n}\n\n// setKnownLeader is used to set the known leader header\nfunc setKnownLeader(resp http.ResponseWriter, known bool) {\n\ts := \"true\"\n\tif !known {\n\t\ts = \"false\"\n\t}\n\tresp.Header().Set(\"X-Nomad-KnownLeader\", s)","sourceCodeStart":894,"sourceCodeEnd":930,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/command/agent/http.go#L894-L930","documentation":"decodeBody in command/agent/http.go decodes JSON HTTP request bodies for Nomad agent API endpoints. It rejects requests whose body is http.NoBody, i.e. an empty body, because the endpoint handlers require a JSON object to decode. Sending no body (or a body-less GET-style request) to a write endpoint that expects a payload triggers this error.","triggerScenarios":"POSTing to ACL endpoints (aclPolicyUpdate, ACLTokenBootstrap, aclTokenUpdate, aclRoleUpsertRequest, aclAuthMethodUpsertRequest) or ExchangeOneTimeToken with an empty request body — e.g. `curl -XPOST /v1/acl/token/bootstrap` with no -d data on a client where the content body is stripped.","commonSituations":"curl POST without -d/--data; HTTP clients that omit a body for POST; a reverse proxy stripping request bodies; calling a write endpoint with the wrong HTTP method tooling that sends no payload.","solutions":["Send a JSON body with the request, e.g. `curl -XPOST -d '{}' $NOMAD_ADDR/v1/acl/token/bootstrap`.","Set Content-Type: application/json and pass the required fields for the endpoint (e.g. Name/Rules for policy upsert).","Use a Nomad API client library that automatically serializes the request struct instead of hand-crafted empty POSTs.","Check any intermediary proxy/gateway is not dropping the request body."],"exampleFix":"// before\ncurl -XPOST $NOMAD_ADDR/v1/acl/policy/my-policy\n// after\ncurl -XPOST -H 'Content-Type: application/json' -d '{\"Name\":\"my-policy\",\"Rules\":\"...\"}' $NOMAD_ADDR/v1/acl/policy/my-policy","handlingStrategy":"validation","validationCode":"// client-side check before POSTing\nbody, _ := json.Marshal(payload)\nif len(body) == 0 {\n    return errors.New(\"refusing to POST: request body is empty\")\n}","typeGuard":null,"tryCatchPattern":"resp, err := http.Post(url, \"application/json\", bytes.NewReader(body))\nif err != nil {\n    return err\n}\nif strings.Contains(readErrHint(resp), \"Request body is empty\") {\n    return fmt.Errorf(\"endpoint %s requires a JSON body; got none\", url)\n}","preventionTips":["Always send a JSON body (even `{}`) to Nomad write endpoints.","Use the official Nomad API client instead of hand-built POSTs.","Set Content-Type: application/json on all mutating requests.","Verify proxies/gateways preserve request bodies."],"tags":["http-api","json","request-body"],"backgroundTag":"empty-request-body","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}