gofiber/fiber · error
%v
Error message
%v
What it means
Returned by DefaultPanicHandler when the recovered panic value is not an error. The handler converts any non-error panic (string, int, struct) into an error via fmt.Errorf("%v", r) so fiber's error chain can carry it. The '%v' deliberately avoids a 'panic: ' prefix that breaks gotestsum reruns.
Source
Thrown at middleware/recover/recover.go:22
"fmt"
"os"
"runtime/debug"
"github.com/gofiber/fiber/v3"
)
// Must not start with "panic: ": the panic was recovered, and that exact prefix
// makes gotestsum treat the whole run as crashed and skip --rerun-fails.
func defaultStackTraceHandler(_ fiber.Ctx, e any) {
fmt.Fprintf(os.Stderr, "recovered panic: %v\n\n%s\n", e, debug.Stack())
}
// DefaultPanicHandler returns r directly if it's an error, and creates a new one with the %v verb otherwise.
func DefaultPanicHandler(_ fiber.Ctx, r any) error {
if err, ok := r.(error); ok {
return err
}
return fmt.Errorf("%v", r)
}
// New creates a new middleware handler
func New(config ...Config) fiber.Handler {
// Set default config
cfg := configDefault(config...)
// Return new handler
return func(c fiber.Ctx) (err error) { //nolint:nonamedreturns // Uses recover() to overwrite the error
// Don't execute middleware if Next returns true
if cfg.Next != nil && cfg.Next(c) {
return c.Next()
}
// Catch panics
defer func() {
if r := recover(); r != nil {
if cfg.EnableStackTrace {View on GitHub (pinned to 9a4c7e57fe)
Solutions
- Fix the underlying panic at its source.
- If you control the panicking code, panic with a proper error so the original value is preserved unchanged.
- Provide a custom Config.PanicHandler to render non-error panics however you need.
Example fix
// before: panicking with a string loses structure
panic("invalid state")
// after: panic with a typed error
var ErrInvalidState = errors.New("invalid state")
panic(ErrInvalidState) Defensive patterns
Strategy: try-catch
Type guard
// isError narrows a recovered panic value to the error interface so you
// can preserve it verbatim instead of re-wrapping via %v.
func isError(r any) (error, bool) {
e, ok := r.(error)
return e, ok
} Try / catch
// Install the recover middleware; DefaultPanicHandler wraps non-error
// panics into an error automatically.
app.Use(recover.New(recover.Config{
EnableStackTrace: true,
PanicHandler: func(c fiber.Ctx, r any) error {
if e, ok := r.(error); ok {
return e // preserve typed errors unchanged
}
return fiber.NewError(fiber.StatusInternalServerError,
fmt.Sprintf("panic: %v", r))
},
})) Prevention
- Always panic with a proper error, not a string or primitive.
- Install recover.New early in the middleware chain.
- Log stack traces (EnableStackTrace:true) to locate panic sources.
- Add unit tests that exercise handlers likely to panic.
When it happens
Trigger: A handler panics with a non-error value (panic("boom"), panic(42), panic(SomeStruct{})) and the recover middleware's default PanicHandler wraps it at recover.go:22.
Common situations: Third-party code panicking with a string; a nil-pointer dereference recovered as a runtime.Error (this branch only triggers for non-error values); legacy code using panic with primitives.
Related errors
- fiber: failed to %s shared state %s value: %w
- fiber: failed to %s shared state %s value: %v
- use: invalid handler %v\n
- use: invalid handler %v
- use: invalid handler %v
AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04).
Data as JSON: /data/errors/105df1e6ca09b1bb.json.
Report an issue: GitHub.