grpc-ecosystem/grpc-gateway · error
must not set request body when http method is GET: %s
Error message
must not set request body when http method is GET: %s
What it means
HTTP GET requests carry parameters only in the URL; the generator rejects google.api.http 'get' rules that also declare a 'body'. A GET with a body is not valid HTTP semantics, so template building fails with the method descriptor name.
Source
Thrown at internal/descriptor/services.go:108
}
meth := &Method{
Service: svc,
MethodDescriptorProto: md,
RequestType: requestType,
ResponseType: responseType,
}
newBinding := func(opts *options.HttpRule, idx int) (*Binding, error) {
var (
httpMethod string
pathTemplate string
)
switch {
case opts.GetGet() != "":
httpMethod = "GET"
pathTemplate = opts.GetGet()
if opts.Body != "" {
return nil, fmt.Errorf("must not set request body when http method is GET: %s", md.GetName())
}
case opts.GetPut() != "":
httpMethod = "PUT"
pathTemplate = opts.GetPut()
case opts.GetPost() != "":
httpMethod = "POST"
pathTemplate = opts.GetPost()
case opts.GetDelete() != "":
httpMethod = "DELETE"
pathTemplate = opts.GetDelete()
if opts.Body != "" && !r.allowDeleteBody {
return nil, fmt.Errorf("must not set request body when http method is DELETE except allow_delete_body option is true: %s", md.GetName())
}
case opts.GetPatch() != "":View on GitHub (pinned to a58a4436a3)
Solutions
- Remove the 'body' field from the google.api.http GET annotation
- Pass parameters via the path template and query parameters instead
- If a request body is truly required, switch the rpc to POST or PUT
- Keep GET to a single request field mapped into the URL
Example fix
// before
option (google.api.http) = { get: "/v1/books/{id}" body: "*" };
// after
option (google.api.http) = { get: "/v1/books/{id}" }; Defensive patterns
Strategy: validation
Validate before calling
if rule.GetGet() != "" && rule.GetBody() != "" {
return fmt.Errorf("rpc %s: GET rule must not declare body", rpc.GetName())
}
err := buildTemplates(rpc) Prevention
- Lint annotations so GET rules never set 'body' (buf lint catches this)
- When migrating POST to GET, delete the body field explicitly
- Document a team convention: GET reads use path/query parameters only
When it happens
Trigger: A rpc's google.api.http option sets both 'get' and 'body' fields; building the template for such a method raises this error immediately when opts.Body != "" under the GetGet() branch.
Common situations: Hand-editing annotations and leaving a 'body: "*"' from a copied PUT/POST rule; tools migrating POST to GET that keep the body field; misunderstandings about GET semantics for large payloads.
Related errors
- must not set request body when http method is DELETE except
- duplicate annotation: method=%s, template=%s
- no target service defined in the file
- only primitive and enum types are allowed in repeated path p
- only primitive and well-known types are allowed in path para
AI-assisted analysis of grpc-ecosystem/grpc-gateway@a58a4436a3 (2026-09-02).
Data as JSON: /api/errors/daa92a4043b128ed.
Report an issue: GitHub.