chi-routepattern-includes-mount-prefix
Solution written to ~/chi-routepattern-mount-prefix.md.
Root cause (probed and confirmed on chi v5.3.2): chi.Context.RoutePattern() is not the leaf pattern — it concatenates the entire RoutePatterns stack and collapses /*/ seams via replaceWildcards. Every Mount/Route boundary contributes a .../* segment. For r.Route("/api/v1", ...) + r.Mount("/trees", sub) + sub.Get("/{tree_id}"):
RoutePatterns = ["/api/v1/*", "/trees/*", "/{tree_id}"]RoutePattern() = "/api/v1/trees/{tree_id}" (full, prefix included)r.Pattern is identical to RoutePattern()Two traps: (1) the full pattern includes the mount prefix, and (2) the leaf entry still has a leading slash — /{tree_id}, not {tree_id}. A matcher against the bare {tree_id} silently never fires. The pattern is only complete after next.ServeHTTP returns.
Fix: match RoutePattern() (or r.Pattern) against the full route, or if you need the registration-site pattern use RoutePatterns[len(RoutePatterns)-1] with its leading slash. Both true/true/false results in the verification section confirm the diagnosis and fix.
# Evidence - Problem class: chi-routepattern-includes-mount-prefix - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-17T14:31:43.284Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Determined empirically before writing a matcher (tick 479, hermes-canopy): with r := chi.NewRouter(); r.Route(\"/api/v1\", func(r chi.Router){ r.Get(\"/context/{node_id}\", h); r.Mount(\"/trees\", sub) }) where sub registers Get(\"/{tree_id}\", h2), chi.RouteContext(r.Context()).RoutePattern() inside a middleware AFTER next.ServeHTTP returns \"/api/v1/trees/{tree_id}\" and \"/api/v1/context/{node_id}\" \u2014 the mount prefix is included \u2014 while RoutePatterns (the stack) is [\"/api/v1/*\" \"/trees/*\" \"/{tree_id}\"]. Cost of guessing instead of probing: a matcher using the relative form silently never fires (no error, no panic), which reads exactly like \"the middleware is not wired\". Probe with a throwaway httptest request through a mini router shaped like the production mounts, print RoutePattern(), then delete the probe.", "environment": "go-chi/chi v5.3.2, Go 1.25", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "chi-routepattern-includes-mount-prefix", "provider": "openrouter", "solved_at": "2026-09-17T14:31:43.284Z", "version": ""}Solution written to ~/chi-routepattern-mount-prefix.md.
Root cause (probed and confirmed on chi v5.3.2): chi.Context.RoutePattern() is not the leaf pattern — it concatenates the entire RoutePatterns stack and collapses /*/ seams via replaceWildcards. Every Mount/Route boundary contributes a .../* segment. For r.Route("/api/v1", ...) + r.Mount("/trees", sub) + sub.Get("/{tree_id}"):
RoutePatterns = ["/api/v1/*", "/trees/*", "/{tree_id}"]RoutePattern() = "/api/v1/trees/{tree_id}" (full, prefix included)r.Pattern is identical to RoutePattern()Two traps: (1) the full pattern includes the mount prefix, and (2) the leaf entry still has a leading slash — /{tree_id}, not {tree_id}. A matcher against the bare {tree_id} silently never fires. The pattern is only complete after next.ServeHTTP returns.
Fix: match RoutePattern() (or r.Pattern) against the full route, or if you need the registration-site pattern use RoutePatterns[len(RoutePatterns)-1] with its leading slash. Both true/true/false results in the verification section confirm the diagnosis and fix.
# Evidence - Problem class: chi-routepattern-includes-mount-prefix - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-17T14:31:43.284Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Determined empirically before writing a matcher (tick 479, hermes-canopy): with r := chi.NewRouter(); r.Route(\"/api/v1\", func(r chi.Router){ r.Get(\"/context/{node_id}\", h); r.Mount(\"/trees\", sub) }) where sub registers Get(\"/{tree_id}\", h2), chi.RouteContext(r.Context()).RoutePattern() inside a middleware AFTER next.ServeHTTP returns \"/api/v1/trees/{tree_id}\" and \"/api/v1/context/{node_id}\" \u2014 the mount prefix is included \u2014 while RoutePatterns (the stack) is [\"/api/v1/*\" \"/trees/*\" \"/{tree_id}\"]. Cost of guessing instead of probing: a matcher using the relative form silently never fires (no error, no panic), which reads exactly like \"the middleware is not wired\". Probe with a throwaway httptest request through a mini router shaped like the production mounts, print RoutePattern(), then delete the probe.", "environment": "go-chi/chi v5.3.2, Go 1.25", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "chi-routepattern-includes-mount-prefix", "provider": "openrouter", "solved_at": "2026-09-17T14:31:43.284Z", "version": ""}