OAS pattern generation without wildcard {$} causes panic in http.ServeMux due to pattern conflicts
When using paths from OAS spec without proper wildcard {$} suffix, the generator registers routes that conflict in http.ServeMux, causing runtime panic. The generated patterns should use "{$}" wildcard to prevent conflicts. This is because Go's http.ServeMux interprets trailing / as a wildcard match, leading to pattern conflicts when multiple routes can match the same path.
Current Problem:
Generated code creates conflicting patterns that cause panic:
panic: pattern "GET /api/test/{id}/test2/" (registered at .../api.gen.go:1001) conflicts with pattern "GET /api/test/test3/" (registered at .../api.gen.go:1000):
GET /api/test/{id}/test2/ and GET /api/test/test3/ both match some paths, like "/api/test/test3/test2/".
But neither is more specific than the other.
GET /api/test/{id}/test2/ matches "/api/test/id/test2/", but GET /api/test/{id}/test2/ doesn't.
GET /api/test/test3/ matches "/api/test/test3/", but GET /api/test/{id}/test2/ doesn't.
goroutine 1 [running]:
net/http.(*ServeMux).register(...)
/opt/homebrew/Cellar/go/1.24.2/libexec/src/net/http/server.go:2872
net/http.(*ServeMux).HandleFunc(0x10000200fad701?, {0x140010b6240?, 0x1050993e8?}, 0x0?)
OAS spec causing the conflict:
openapi: 3.0.3
info:
title: test
description: test
version: 1.0.0
paths:
/api/test/{id}/test2/:
get:
operationId: test1
/api/test/test3/:
get:
operationId: test2
Generated code that causes panic:
func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
m := options.BaseRouter
if m == nil {
m = http.NewServeMux()
}
if options.ErrorHandlerFunc == nil {
options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
http.Error(w, err.Error(), http.StatusBadRequest)
}
}
wrapper := ServerInterfaceWrapper{
Handler: si,
HandlerMiddlewares: options.Middlewares,
ErrorHandlerFunc: options.ErrorHandlerFunc,
}
m.HandleFunc("GET "+options.BaseURL+"/api/test/test3/", wrapper.Test2)
m.HandleFunc("GET "+options.BaseURL+"/api/test/{id}/test2/", wrapper.Test1)
return m
}
Working solution with {$} wildcard:
func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
// ... same setup code ...
m.HandleFunc("GET "+options.BaseURL+"/api/test/test3/{$}", wrapper.Test2)
m.HandleFunc("GET "+options.BaseURL+"/api/test/{id}/test2/", wrapper.Test1)
return m
}
Proposed Solution:
Add an option to generate wildcard {$} suffix for exact path matching in spec file or detect and fix pattern conflict while generating code
Related issue: https://github.com/oapi-codegen/oapi-codegen/issues/1952