{"record":{"id":"025e8f33c9fd9f0b","repo":"gofiber/fiber","slug":"runtime-goexit-called-in-handler-or-server-panic","errorCode":null,"errorMessage":"runtime.Goexit() called in handler or server panic","messagePattern":"runtime\\.Goexit\\(\\) called in handler or server panic","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"error.go","lineNumber":20,"sourceCode":"\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\n\t\"github.com/gofiber/schema\"\n)\n\n// Wrap and return this for unreachable code if panicking is undesirable (i.e., in a handler).\n// Unexported because users will hopefully never need to see it.\nvar errUnreachable = errors.New(\"fiber: unreachable code, please create an issue at github.com/gofiber/fiber\")\n\n// General errors\nvar (\n\tErrGracefulTimeout = errors.New(\"shutdown: graceful timeout has been reached, exiting\")\n\t// ErrNotRunning indicates that a Shutdown method was called when the server was not running.\n\tErrNotRunning = errors.New(\"shutdown: server is not running\")\n\t// ErrHandlerExited is returned by App.Test if a handler panics or calls runtime.Goexit().\n\tErrHandlerExited = errors.New(\"runtime.Goexit() called in handler or server panic\")\n\t// ErrNoViewEngineConfigured indicates that a helper requiring a view engine was invoked without one configured.\n\tErrNoViewEngineConfigured = errors.New(\"fiber: no view engine configured\")\n\t// ErrAutoCertWithCertFile indicates AutoCertManager cannot be used with CertFile/CertKeyFile.\n\tErrAutoCertWithCertFile = errors.New(\"tls: AutoCertManager cannot be combined with CertFile/CertKeyFile\")\n\t// ErrRouteNotRepresentable indicates a route whose path no relative URL can\n\t// name, so Route.URL, GetRouteURL and Redirect().Route cannot compose one.\n\t// A path starting with two or more slashes is such a route: the URL that\n\t// would reach it opens an authority instead.\n\tErrRouteNotRepresentable = errors.New(\"router: route path cannot be expressed as a relative URL\")\n)\n\n// Fiber redirection errors\nvar (\n\tErrRedirectBackNoFallback = NewError(StatusInternalServerError, \"Referer not found, you have to enter fallback URL for redirection.\")\n)\n\n// Range errors\nvar (","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/error.go#L2-L38","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\napp.Get(\"/boom\", func(c fiber.Ctx) error {\n    panic(\"oops\")\n})\n// after\napp.Use(recover.New())\napp.Get(\"/boom\", func(c fiber.Ctx) error {\n    panic(\"oops\")\n})","handlingStrategy":"try-catch","validationCode":"// Ensure a recovery middleware is mounted so handler panics never unwind\n// the goroutine. Register it before any route that can panic.\napp.Use(recover.New())","typeGuard":"// isHandlerExited reports whether App.Test aborted because the handler\n// exited abnormally (panic or runtime.Goexit).\nfunc isHandlerExited(err error) bool {\n    return errors.Is(err, fiber.ErrHandlerExited)\n}","tryCatchPattern":"resp, err := app.Test(req)\nif err != nil {\n    if errors.Is(err, fiber.ErrHandlerExited) {\n        t.Fatalf(\"handler panicked or called runtime.Goexit during test\")\n    }\n    t.Fatalf(\"test request failed: %v\", err)\n}","preventionTips":["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."],"tags":["testing","handler","panic","lifecycle","app-test"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}