runtime.ServeMux: wrong handler chosen

Author: movsbCreated Jul 28, 2025Updated Jul 23, 2026

Bug Report

Adding custom routes to the mux | gRPC-Gateway

The gRPC-Gateway allows you to add custom routes to the serve mux, for example, if you want to support a use case that isn’t supported by the gRPC-Gateway, like file uploads.

So, I have a ListFiles method in gRPC service proto which list files: /v3/files. And I registered another GetFile method manually using HandlePath: /v3/files/{path=**}.

The final routing tree may be like the following:

go
func main() {
	mux := runtime.NewServeMux()
	mux.HandlePath(`GET`, `/v3/files`, func(w http.ResponseWriter, r *http.Request, pathParams map[string]string) {
		fmt.Fprintln(w, 1, pathParams)
	})
	mux.HandlePath(`GET`, `/v3/files/{path=**}`, func(w http.ResponseWriter, r *http.Request, pathParams map[string]string) {
		fmt.Fprintln(w, 2, pathParams)
	})
	http.ListenAndServe(`:8080`, mux)
}

Result:

bash
$ curl localhost:8080/v3/files
2 map[path:]
$ curl localhost:8080/v3/files/a.txt
2 map[path:a.txt]

I'm expecting that the first request is routing the first handler, which prints 1.

Swapping the handling order fixes this problem, but I just think that the handling order shouldn't matter:

  1. https://github.com/grpc-ecosystem/grpc-gateway/blob/031e8453ef0293ed15626100d87999a1becc2347/runtime/mux.go#L354
  2. https://github.com/grpc-ecosystem/grpc-gateway/blob/031e8453ef0293ed15626100d87999a1becc2347/runtime/mux.go#L412

The handlers added later will be put into the front of the handlers slice, and will be used firstly.

Source: grpc-ecosystem/grpc-gateway