hashicorp/nomad · error

Request body is empty

Error message

Request body is empty

What it means

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.

Source

Thrown at command/agent/http.go:912

		}
		// write response
		if obj != nil {
			resp.Write(obj)
		}
	}
	return f
}

// isAPIClientError returns true if the passed http code represents a client error
func isAPIClientError(code int) bool {
	return 400 <= code && code <= 499
}

// decodeBody is used to decode a JSON request body
func decodeBody(req *http.Request, out any) error {

	if req.Body == http.NoBody {
		return errors.New("Request body is empty")
	}

	dec := json.NewDecoder(req.Body)
	return dec.Decode(&out)
}

// setIndex is used to set the index response header
func setIndex(resp http.ResponseWriter, index uint64) {
	resp.Header().Set("X-Nomad-Index", strconv.FormatUint(index, 10))
}

// setKnownLeader is used to set the known leader header
func setKnownLeader(resp http.ResponseWriter, known bool) {
	s := "true"
	if !known {
		s = "false"
	}
	resp.Header().Set("X-Nomad-KnownLeader", s)

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Send a JSON body with the request, e.g. `curl -XPOST -d '{}' $NOMAD_ADDR/v1/acl/token/bootstrap`.
  2. Set Content-Type: application/json and pass the required fields for the endpoint (e.g. Name/Rules for policy upsert).
  3. Use a Nomad API client library that automatically serializes the request struct instead of hand-crafted empty POSTs.
  4. Check any intermediary proxy/gateway is not dropping the request body.

Example fix

// before
curl -XPOST $NOMAD_ADDR/v1/acl/policy/my-policy
// after
curl -XPOST -H 'Content-Type: application/json' -d '{"Name":"my-policy","Rules":"..."}' $NOMAD_ADDR/v1/acl/policy/my-policy
Defensive patterns

Strategy: validation

Validate before calling

// client-side check before POSTing
body, _ := json.Marshal(payload)
if len(body) == 0 {
    return errors.New("refusing to POST: request body is empty")
}

Try / catch

resp, err := http.Post(url, "application/json", bytes.NewReader(body))
if err != nil {
    return err
}
if strings.Contains(readErrHint(resp), "Request body is empty") {
    return fmt.Errorf("endpoint %s requires a JSON body; got none", url)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/8c95e0b54977ace1. Report an issue: GitHub.