Skip to content

Commit 94a0c5f

Browse files
fadymondyclaude
andcommitted
fix(kernel)!: register day-zero middleware before providers mount routes
togo.New() called Router.Use() AFTER applyProviders(), but providers (auth) mount routes during applyProviders → chi panic 'all middlewares must be defined before routes'. Reordered: Use/NotFound/MethodNotAllowed first, then applyProviders. Regression test added. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent fc49494 commit 94a0c5f

2 files changed

Lines changed: 29 additions & 2 deletions

File tree

kernel.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,14 @@ func New() *Kernel {
6666
plugins: Discovered(),
6767
}
6868
k.Log = defaultLogger() // baseline; the log plugin (if installed) overrides it
69-
k.applyProviders()
70-
// Day-zero error handling + logging, applied before any routes are mounted.
69+
// Day-zero middleware MUST be registered before any provider mounts routes —
70+
// chi forbids Use() after routes exist (e.g. the auth plugin adds routes).
7171
k.Router.Use(k.recovery, k.requestLogger)
7272
// The Go backend only serves API/GraphQL/docs, so unmatched routes return JSON.
7373
k.Router.NotFound(jsonErrorHandler(http.StatusNotFound, "not found"))
7474
k.Router.MethodNotAllowed(jsonErrorHandler(http.StatusMethodNotAllowed, "method not allowed"))
75+
// Providers run last: some (auth) mount routes + their own middleware.
76+
k.applyProviders()
7577
return k
7678
}
7779

kernel_mw_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package togo
2+
3+
import (
4+
"net/http"
5+
"testing"
6+
)
7+
8+
// A provider that mounts routes + its own middleware (like auth) must not make
9+
// New() panic ("Use after routes"). Regression for the chi ordering bug.
10+
func TestNewWithRouteMountingProvider(t *testing.T) {
11+
RegisterProviderFunc("test-routes", PriorityLate, func(k *Kernel) error {
12+
k.Router.Use(func(next http.Handler) http.Handler { return next })
13+
k.Router.Get("/_test", func(w http.ResponseWriter, r *http.Request) {})
14+
return nil
15+
})
16+
defer func() {
17+
if r := recover(); r != nil {
18+
t.Fatalf("New() panicked: %v", r)
19+
}
20+
}()
21+
k := New()
22+
if k.Router == nil {
23+
t.Fatal("nil router")
24+
}
25+
}

0 commit comments

Comments
 (0)