From bf4ae219746d3fe3be9a90fe230a439e41aea302 Mon Sep 17 00:00:00 2001 From: sneak Date: Thu, 15 Oct 2026 10:26:04 +0000 Subject: [PATCH] Label requests for a subrouter's own path unmatched in metrics For /v1 and /v1/, the path the image subrouter is mounted at, chi's Find answers that path as the pattern without asking the subrouter, which chi hands the request as / and which has no route there, so the router answers 404. routePattern now asks the subrouter mounted there whether it has a route for /, and labels the request "unmatched" when it has none. Model: opus-5-5 --- internal/middleware/middleware.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/internal/middleware/middleware.go b/internal/middleware/middleware.go index 274ac50..4745a86 100644 --- a/internal/middleware/middleware.go +++ b/internal/middleware/middleware.go @@ -8,6 +8,7 @@ import ( "net/http" "net/netip" "regexp" + "strings" "time" basicauth "github.com/99designs/basicauth-go" @@ -250,6 +251,17 @@ func routePattern(r *http.Request) string { } pattern = rctx.Routes.Find(chi.NewRouteContext(), r.Method, path) + + // For the path a subrouter is mounted at, such as /v1 or /v1/, Find + // answers that path without asking the subrouter, which chi hands + // the request as /. + for _, route := range rctx.Routes.Routes() { + if route.SubRoutes != nil && + route.Pattern == strings.TrimSuffix(pattern, "/")+"/*" && + !route.SubRoutes.Match(chi.NewRouteContext(), r.Method, "/") { + pattern = "" + } + } } if pattern == "" {