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

  1. Register the Recover middleware (middleware/recover) so handler panics are caught before they unwind the goroutine.
  2. Search the handler chain for runtime.Goexit calls and replace them with a normal return error.
  3. 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

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)