gofiber/fiber · critical
runtime.Goexit() called in handler or server panic
Error message
runtime.Goexit() called in handler or server panic
What it means
ErrHandlerExited is returned by App.Test (app.go:1443) when the goroutine running app.server.ServeConn(conn) returns without setting the deferred returned flag. That happens only when the handler chain calls runtime.Goexit() or panics with a value the fasthttp recovery does not catch, both of which skip the returned=true assignment and fall into the deferred send. It is a test-time signal that handler control flow exited abnormally.
Solutions
- Register the Recover middleware (middleware/recover) so handler panics are caught before they unwind the goroutine.
- Search the handler chain for runtime.Goexit calls and replace them with a normal return error.
- If a third-party dependency calls log.Fatal/os.Exit under test, refactor it to return an error instead.
Example fix
// before
app.Get("/boom", func(c fiber.Ctx) error {
panic("oops")
})
// after
app.Use(recover.New())
app.Get("/boom", func(c fiber.Ctx) error {
panic("oops")
}) Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure a recovery middleware is mounted so handler panics never unwind // the goroutine. Register it before any route that can panic. app.Use(recover.New())
Type guard
// isHandlerExited reports whether App.Test aborted because the handler
// exited abnormally (panic or runtime.Goexit).
func isHandlerExited(err error) bool {
return errors.Is(err, fiber.ErrHandlerExited)
} Try / catch
resp, err := app.Test(req)
if err != nil {
if errors.Is(err, fiber.ErrHandlerExited) {
t.Fatalf("handler panicked or called runtime.Goexit during test")
}
t.Fatalf("test request failed: %v", err)
} Prevention
- Always mount middleware/recover so panics are caught before they unwind the goroutine.
- Search the handler chain for runtime.Goexit and replace it with a returned error.
- Avoid log.Fatal/os.Exit inside handlers; they terminate the process or unwind through Goexit.
When it happens
Trigger: Calling app.Test(req) where the registered handler calls runtime.Goexit() directly, or where a panic escapes the recovery middleware (for example because Recovery is misconfigured or absent and a handler deep in the chain panics). The deferred closure in app.go:1441-1447 observes the non-return and sends ErrHandlerExited on the channel.
Common situations: Unit tests that exercise handlers which call runtime.Goexit (sometimes via test-framework helpers); a handler panic with a nil recovery middleware; a handler that calls os.Exit or a log.Fatal that unwinds through Goexit semantics under test.
Related errors
AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11).
Data as JSON: /api/errors/025e8f33c9fd9f0b.
Report an issue: GitHub.
Appendix: source
Thrown at error.go:20
import (
"encoding/json"
"errors"
"github.com/gofiber/schema"
)
// Wrap and return this for unreachable code if panicking is undesirable (i.e., in a handler).
// Unexported because users will hopefully never need to see it.
var errUnreachable = errors.New("fiber: unreachable code, please create an issue at github.com/gofiber/fiber")
// General errors
var (
ErrGracefulTimeout = errors.New("shutdown: graceful timeout has been reached, exiting")
// ErrNotRunning indicates that a Shutdown method was called when the server was not running.
ErrNotRunning = errors.New("shutdown: server is not running")
// ErrHandlerExited is returned by App.Test if a handler panics or calls runtime.Goexit().
ErrHandlerExited = errors.New("runtime.Goexit() called in handler or server panic")
// ErrNoViewEngineConfigured indicates that a helper requiring a view engine was invoked without one configured.
ErrNoViewEngineConfigured = errors.New("fiber: no view engine configured")
// ErrAutoCertWithCertFile indicates AutoCertManager cannot be used with CertFile/CertKeyFile.
ErrAutoCertWithCertFile = errors.New("tls: AutoCertManager cannot be combined with CertFile/CertKeyFile")
// ErrRouteNotRepresentable indicates a route whose path no relative URL can
// name, so Route.URL, GetRouteURL and Redirect().Route cannot compose one.
// A path starting with two or more slashes is such a route: the URL that
// would reach it opens an authority instead.
ErrRouteNotRepresentable = errors.New("router: route path cannot be expressed as a relative URL")
)
// Fiber redirection errors
var (
ErrRedirectBackNoFallback = NewError(StatusInternalServerError, "Referer not found, you have to enter fallback URL for redirection.")
)
// Range errors
var (View on GitHub (pinned to a105acad6c)