#4844·gin

A `/:name` route does not match `/b` when a static `/b/` route is also registered

Author: DRMacIverCreated Sep 22, 2026Updated Sep 22, 2026

Description

With the routes /b/ and /:name registered, GET /b is not served by /:name: it is a 404, or with RedirectTrailingSlash (the default) a 301 to /b/. The mirror shape does the same: with /a/b and /:p/b/, GET /a/b/ is a 404. GET /c is served by /:name as expected, and a static route /b/x beside /:name does not stop GET /b from matching /:name; a static route that differs from the request by only a trailing slash does.

Gin Version

v1.12.0, and master at 3b08cd7 (same output).

Can you reproduce the bug?

Yes

Source Code

go
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/gin-gonic/gin"
)

func get(routes []string, path string, redirectTrailingSlash bool) {
	r := gin.New()
	r.RedirectTrailingSlash = redirectTrailingSlash
	for _, route := range routes {
		r.GET(route, func(c *gin.Context) { c.String(200, "%s %v", route, c.Params) })
	}
	w := httptest.NewRecorder()
	r.ServeHTTP(w, httptest.NewRequest(http.MethodGet, path, nil))
	fmt.Printf("routes %v, GET %s: %d %q Location=%q\n", routes, path, w.Code, w.Body.String(), w.Header().Get("Location"))
}

func main() {
	gin.SetMode(gin.ReleaseMode)
	get([]string{"/b/", "/:name"}, "/b", false)
	get([]string{"/a/b", "/:p/b/"}, "/a/b/", false)
	get([]string{"/b/", "/:name"}, "/c", false)
	get([]string{"/b/x", "/:name"}, "/b", false)
	get([]string{"/b/", "/:name"}, "/b", true)
}

Output:

routes [/b/ /:name], GET /b: 404 "404 page not found" Location=""
routes [/a/b /:p/b/], GET /a/b/: 404 "404 page not found" Location=""
routes [/b/ /:name], GET /c: 200 "/:name [{name c}]" Location=""
routes [/b/x /:name], GET /b: 200 "/:name [{name b}]" Location=""
routes [/b/ /:name], GET /b: 301 "<a href=\"/b/\">Moved Permanently</a>.\n\n" Location="/b/"

I expected the first two requests to be served like the third and fourth, with name = "b" and p = "a", and the last one to be served by /:name rather than redirected to the /b/ handler, since a route matching the request as sent exists.

Go Version

go1.27.1

Operating System

macOS (darwin/arm64); the requests above are served through httptest, nothing OS-specific.

BTW, this was found by an automated program that writes property-based tests for various open source projects using hegel (but it has been reviewed by hand before reporting). We've also potentially found (but not yet hand validated) 10 other bugs in gin. You can see the tests at https://github.com/hegeldev/hegel-zoo/tree/main/targets/go/gin. Let us know if you would like us to file the other bugs found and/or contribute the tests. NB the tests are currently LLM generated and probably not yet suitable for inclusion as is, but we're happy to help get them into a better state if you want them.