Skip to content

OAS pattern generation without wildcard {$} causes panic in http.ServeMux due to pattern conflicts #2065

Description

@olzhas-sabiyev

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: #1952

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions