{"record":{"id":"af5d997fb911117c","repo":"grpc/grpc-go","slug":"invalid-grpc-request-method-q","errorCode":null,"errorMessage":"invalid gRPC request method %q","messagePattern":"invalid gRPC request method %q","errorType":"http","errorClass":null,"httpStatus":405,"severity":"error","filePath":"internal/transport/handler_server.go","lineNumber":58,"sourceCode":"\t\"google.golang.org/grpc/internal/grpclog\"\n\t\"google.golang.org/grpc/internal/grpcutil\"\n\t\"google.golang.org/grpc/mem\"\n\t\"google.golang.org/grpc/metadata\"\n\t\"google.golang.org/grpc/peer\"\n\t\"google.golang.org/grpc/stats\"\n\t\"google.golang.org/grpc/status\"\n\t\"google.golang.org/protobuf/proto\"\n)\n\n// NewServerHandlerTransport returns a ServerTransport handling gRPC from\n// inside an http.Handler, or writes an HTTP error to w and returns an error.\n// It requires that the http Server supports HTTP/2.\nfunc NewServerHandlerTransport(w http.ResponseWriter, r *http.Request, stats stats.Handler, bufferPool mem.BufferPool) (ServerTransport, error) {\n\tif r.Method != http.MethodPost {\n\t\tw.Header().Set(\"Allow\", http.MethodPost)\n\t\tmsg := fmt.Sprintf(\"invalid gRPC request method %q\", r.Method)\n\t\thttp.Error(w, msg, http.StatusMethodNotAllowed)\n\t\treturn nil, errors.New(msg)\n\t}\n\tcontentType := r.Header.Get(\"Content-Type\")\n\t// TODO: do we assume contentType is lowercase? we did before\n\tcontentSubtype, validContentType := grpcutil.ContentSubtype(contentType)\n\tif !validContentType {\n\t\tmsg := fmt.Sprintf(\"invalid gRPC request content-type %q\", contentType)\n\t\thttp.Error(w, msg, http.StatusUnsupportedMediaType)\n\t\treturn nil, errors.New(msg)\n\t}\n\tif r.ProtoMajor != 2 {\n\t\tmsg := \"gRPC requires HTTP/2\"\n\t\thttp.Error(w, msg, http.StatusHTTPVersionNotSupported)\n\t\treturn nil, errors.New(msg)\n\t}\n\tif _, ok := w.(http.Flusher); !ok {\n\t\tmsg := \"gRPC requires a ResponseWriter supporting http.Flusher\"\n\t\thttp.Error(w, msg, http.StatusInternalServerError)\n\t\treturn nil, errors.New(msg)","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/transport/handler_server.go#L40-L76","documentation":"Returned by NewServerHandlerTransport when an incoming HTTP request uses any method other than POST. The gRPC over HTTP/2 wire protocol requires POST for all RPCs; the handler writes a 405 Method Not Allowed and returns this error. The check lives at internal/transport/handler_server.go:54-58.","triggerScenarios":"Routing a non-POST request (GET, PUT, OPTIONS, HEAD) into grpc.Server.ServeHTTP via the http.Handler transport; a health-check or browser preflight hitting the gRPC endpoint; a reverse proxy forwarding the wrong method.","commonSituations":"Load balancer health checks using GET against the gRPC path; CORS preflight (OPTIONS) reaching the handler; curl without -X POST; misconfigured gateway that rewrites the method.","solutions":["Ensure only POST requests reach the gRPC handler; reject/redirect other methods at the proxy or router layer.","For health checks, point them at a dedicated HTTP health endpoint instead of the gRPC service path.","Handle CORS preflight (OPTIONS) in middleware before the request reaches grpc.Server.ServeHTTP.","If serving gRPC and REST on the same mux, route by method and content-type to the correct handler."],"exampleFix":"// before\nhttp.Handle(\"/helloworld.Greeter/\", grpcServer)\n// a GET to that path yields 405 + the error\n\n// after\nmux := http.NewServeMux()\nmux.HandleFunc(\"/healthz\", healthHandler) // GET health checks land here\nmux.Handle(\"/helloworld.Greeter/\", grpcServer) // only POST gRPC here","handlingStrategy":"validation","validationCode":"if r.Method != http.MethodPost {\n    http.Error(w, \"use POST\", http.StatusMethodNotAllowed)\n    return\n}\nsrv.ServeHTTP(w, r)","typeGuard":null,"tryCatchPattern":"if _, err := transport.NewServerHandlerTransport(w, r, stats, pool); err != nil {\n    // already wrote the HTTP error; just log\n    log.Printf(\"non-gRPC request rejected: %v\", err)\n}","preventionTips":["Route health checks and non-POST traffic to separate HTTP handlers.","Handle OPTIONS/CORS preflight before delegating to grpc.Server.ServeHTTP.","Configure ingress/proxy to only forward POST to gRPC paths."],"tags":["go","grpc","transport","http","grpc-web"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}