grpc/grpc-go · warning

invalid gRPC request content-type

Error message

invalid gRPC request content-type %q

What it means

Returned by NewServerHandlerTransport when the Content-Type header is not a valid gRPC content type. gRPC requires Content-Type to start with 'application/grpc' (optionally followed by '+subtype' or ';subtype'). If the header is missing, empty, or any other value, the request is rejected with HTTP 415 Unsupported Media Type.

Solutions

  1. Ensure the client sends 'Content-Type: application/grpc' (or 'application/grpc+proto').
  2. If serving gRPC-Web, ensure the transcoding proxy sets the correct content type.
  3. Separate HTTP/JSON endpoints from gRPC endpoints in your routing.
  4. Check that proxies and CDNs preserve the Content-Type header.

Example fix

// before: missing content-type
curl -X POST http://localhost:8080/myapp.Service/Method
// after: include gRPC content-type
curl -X POST -H "Content-Type: application/grpc" \
  http://localhost:8080/myapp.Service/Method
Defensive patterns

Strategy: validation

Validate before calling

// Ensure requests to the gRPC endpoint have the correct content-type.
// In a reverse proxy, validate and set Content-Type.
if !strings.HasPrefix(r.Header.Get("Content-Type"), "application/grpc") {
    http.Error(w, "gRPC requires application/grpc content-type", 415)
    return
}

Try / catch

st, err := transport.NewServerHandlerTransport(w, r, stats, pool)
if err != nil {
    // HTTP error already written; log and return
    log.Printf("gRPC transport rejected request: %v", err)
    return
}

Prevention

When it happens

Trigger: An HTTP request to the gRPC handler transport without a Content-Type header, or with a non-gRPC content type like 'application/json' or 'text/plain'. The check via grpcutil.ContentSubtype at handler_server.go:62-66 returns false.

Common situations: Non-gRPC HTTP client hitting the gRPC endpoint; a gRPC-Web proxy that strips or doesn't set Content-Type; curl without the -H content-type flag; browser preflight or direct fetch without gRPC framing; service mesh or CDN stripping content-type headers.

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/4b387ba61b056b17. Report an issue: GitHub.

Appendix: source

Thrown at internal/transport/handler_server.go:66

)

// NewServerHandlerTransport returns a ServerTransport handling gRPC from
// inside an http.Handler, or writes an HTTP error to w and returns an error.
// It requires that the http Server supports HTTP/2.
func NewServerHandlerTransport(w http.ResponseWriter, r *http.Request, stats stats.Handler, bufferPool mem.BufferPool) (ServerTransport, error) {
	if r.Method != http.MethodPost {
		w.Header().Set("Allow", http.MethodPost)
		msg := fmt.Sprintf("invalid gRPC request method %q", r.Method)
		http.Error(w, msg, http.StatusMethodNotAllowed)
		return nil, errors.New(msg)
	}
	contentType := r.Header.Get("Content-Type")
	// TODO: do we assume contentType is lowercase? we did before
	contentSubtype, validContentType := grpcutil.ContentSubtype(contentType)
	if !validContentType {
		msg := fmt.Sprintf("invalid gRPC request content-type %q", contentType)
		http.Error(w, msg, http.StatusUnsupportedMediaType)
		return nil, errors.New(msg)
	}
	if r.ProtoMajor != 2 {
		msg := "gRPC requires HTTP/2"
		http.Error(w, msg, http.StatusHTTPVersionNotSupported)
		return nil, errors.New(msg)
	}
	if _, ok := w.(http.Flusher); !ok {
		msg := "gRPC requires a ResponseWriter supporting http.Flusher"
		http.Error(w, msg, http.StatusInternalServerError)
		return nil, errors.New(msg)
	}

	var localAddr net.Addr
	if la := r.Context().Value(http.LocalAddrContextKey); la != nil {
		localAddr, _ = la.(net.Addr)
	}
	var authInfo credentials.AuthInfo
	if r.TLS != nil {

View on GitHub (pinned to 0c51461d27)