Fiber Recover middleware panic handling and custom error handler integration
0 reputation · 17 Sept 2022, 06:26 UTC
0 reputation · 17 Sept 2022, 06:26 UTC
The Fiber Recover middleware is designed to intercept panics during the request-response cycle to prevent server crashes. While the middleware can be configured with a custom handler to log stack traces, there is a need to clarify the precise execution order when both a custom recovery handler and a global Fiber error handler are defined.
The goal is to ensure that recovery events result in a standardized HTTP response that adheres to the application's global error schema without bypassing the centralized error management logic.
33775 reputation · 17 Sept 2022, 17:14 UTC
1. Does the Recover middleware pass the recovered panic as an error to the global Fiber error handler?
Yes. When a panic occurs, Recover captures it and, unless the custom recovery handler explicitly handles the response, forwards the recovered panic as an error to the next middleware in the chain – typically the global error handler.
2. Under what conditions does the custom recovery handler override the global error handler’s response?
The custom handler overrides the global error handler only when it writes a response to the c context and returns nil. In that case Recover stops propagation, and the global error handler is never invoked for that request.
The typical request pipeline looks like this:
Recover middleware.Recover intercepts the panic and invokes the custom recovery handler (if configured).nil after writing a response, Recover halts further processing.Recover forwards that error to the next middleware.c.Response() (e.g., sets status code, writes body).nil.nil indicates no further error propagation, Recover does not call the global error handler.Otherwise, if the custom handler returns a non‑nil error, the error is propagated to the global error handler, which then applies the standard error schema.
app := fiber.New()
// Global error handler
app.Use(func(c *fiber.Ctx) error {
if err := c.Next(); err != nil {
// Format according to global schema
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": err.Error(),
})
}
return nil
})
// Custom recover handler
recoverHandler := func(c *fiber.Ctx, err interface{}) error {
// Example: log and return nil to override
log.Printf("panic recovered: %v", err)
return c.Status(fiber.StatusServiceUnavailable).JSON(fiber.Map{
"message": "service temporarily unavailable",
})
}
app.Use(fiber.Recover(fiber.RecoverConfig{Handler: recoverHandler}))
// Route that panics
app.Get("/panic", func(c *fiber.Ctx) error {
panic("boom")
})
app.Listen(3000)
Run the server and hit /panic. If the custom handler returns nil, you’ll see the 503 response and no invocation of the global error handler. Change the handler to return an error (e.g., return errors.New("recovery error")) and the global handler will format the response instead.
Recover before the global error handler to ensure the error is caught early.v2.x the API signatures are stable; older versions (<2.0) may have subtle differences.To confirm the exact behavior in your setup, could you specify the order in which you register the Recover middleware and the global error handler?
Use comments to ask for clarification. Post a solution as an answer.
33,775 reputation · 17 Sept 2022, 10:05 UTC
When a panic is caught, Recover gives the custom Handler the panic value as an interface{}. If the Handler writes a response and returns nil, Recover treats the request as finished and does not invoke the global error handler. If the Handler instead returns an error (or calls c.Next(err)), that error continues down the chain and reaches any global error middleware placed after Recover. Notably, returning nil without writing a response lets Recover continue with a nil error, which results in no error being passed forward.