{"record":{"id":"daa92a4043b128ed","repo":"grpc-ecosystem/grpc-gateway","slug":"must-not-set-request-body-when-http-method-is-get","errorCode":null,"errorMessage":"must not set request body when http method is GET: %s","messagePattern":"must not set request body when http method is GET: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/descriptor/services.go","lineNumber":108,"sourceCode":"\t}\n\tmeth := &Method{\n\t\tService:               svc,\n\t\tMethodDescriptorProto: md,\n\t\tRequestType:           requestType,\n\t\tResponseType:          responseType,\n\t}\n\n\tnewBinding := func(opts *options.HttpRule, idx int) (*Binding, error) {\n\t\tvar (\n\t\t\thttpMethod   string\n\t\t\tpathTemplate string\n\t\t)\n\t\tswitch {\n\t\tcase opts.GetGet() != \"\":\n\t\t\thttpMethod = \"GET\"\n\t\t\tpathTemplate = opts.GetGet()\n\t\t\tif opts.Body != \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"must not set request body when http method is GET: %s\", md.GetName())\n\t\t\t}\n\n\t\tcase opts.GetPut() != \"\":\n\t\t\thttpMethod = \"PUT\"\n\t\t\tpathTemplate = opts.GetPut()\n\n\t\tcase opts.GetPost() != \"\":\n\t\t\thttpMethod = \"POST\"\n\t\t\tpathTemplate = opts.GetPost()\n\n\t\tcase opts.GetDelete() != \"\":\n\t\t\thttpMethod = \"DELETE\"\n\t\t\tpathTemplate = opts.GetDelete()\n\t\t\tif opts.Body != \"\" && !r.allowDeleteBody {\n\t\t\t\treturn nil, fmt.Errorf(\"must not set request body when http method is DELETE except allow_delete_body option is true: %s\", md.GetName())\n\t\t\t}\n\n\t\tcase opts.GetPatch() != \"\":","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/grpc-ecosystem/grpc-gateway/blob/a58a4436a376a4bcc7d8f10c4d4f919a8438bba9/internal/descriptor/services.go#L90-L126","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\noption (google.api.http) = { get: \"/v1/books/{id}\" body: \"*\" };\n// after\noption (google.api.http) = { get: \"/v1/books/{id}\" };","handlingStrategy":"validation","validationCode":"if rule.GetGet() != \"\" && rule.GetBody() != \"\" {\n    return fmt.Errorf(\"rpc %s: GET rule must not declare body\", rpc.GetName())\n}\nerr := buildTemplates(rpc)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["http","annotation","protobuf","validation"],"backgroundTag":"get-request-with-body","analyzedSha":"a58a4436a376a4bcc7d8f10c4d4f919a8438bba9","analyzedAt":"2026-09-02T10:28:31.537Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T16:17:10.729Z"}