gofiber/fiber · critical
use: invalid handler
Error message
use: invalid handler %v
What it means
Inside App.Use, arguments are dispatched by type: string becomes a prefix, *App becomes a sub-app to mount, []string becomes multiple prefixes, and anything else is funneled through toFiberHandler. If none match, the app panics showing the Go type of the offending argument. This is a route-registration-time programming error.
Solutions
- Check the panic output for the rejected type and locate that argument in your app.Use(...) call.
- Convert the argument to func(*fiber.Ctx) error or to a *fiber.App (for mounting) before passing.
- For mounting a sub-app, pass *fiber.App explicitly: app.Use("/sub", subApp).
- For a Group, use group.Use(...) on the group, not app.Use(group).
Example fix
// before
subApp := fiber.New()
app.Use(subApp.Group("/api")) // Group is not accepted here
// after
api := subApp.Group("/api")
app.Use("/api", subApp) Defensive patterns
Strategy: type-guard
Validate before calling
// Classify Use arguments before calling app.Use
func classifyUseArg(arg any) (prefix string, sub *fiber.App, h fiber.Handler, err error) {
switch v := arg.(type) {
case string: return v, nil, nil, nil
case *fiber.App: return "", v, nil, nil
case fiber.Handler, func(*fiber.Ctx) error:
return "", nil, v.(fiber.Handler), nil
}
return "", nil, nil, fmt.Errorf("unsupported Use arg: %T", arg)
} Type guard
func isUseableArg(v any) bool {
switch v.(type) {
case string, *fiber.App, fiber.Handler, func(*fiber.Ctx) error, []string:
return true
}
return false
} Try / catch
// Wrap app.Use calls in tests to catch type mistakes
func useSafely(app *fiber.App, args ...any) (err error) {
defer func() {
if r := recover(); r != nil { err = fmt.Errorf("use: %v", r) }
}()
app.Use(args...)
return nil
} Prevention
- Mount sub-apps with app.Use(prefix, subApp) explicitly.
- Apply middleware on the Group via group.Use, not on the parent app.
- Add a smoke test that builds the router to catch Use-type panics.
When it happens
Trigger: Calling app.Use(someInt), app.Use(myStruct), or app.Use(aFuncWithWrongSignature). The message uses reflect.TypeOf(arg) so you can see exactly what type was rejected.
Common situations: Passing a *Router or *Group where *App or a Handler was expected; passing a config struct; passing a handler chain built by a helper that returned the wrong type; refactor that changed Use calls.
Related errors
- : invalid handler # (%T)
- use: invalid handler
- use: invalid handler
- basicauth: charset must be UTF-8
- [CORS] Configuration error: When 'AllowCredentials' is set…
AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11).
Data as JSON: /api/errors/743489c219cb51b6.
Report an issue: GitHub.
Appendix: source
Thrown at app.go:1046
// This method will match all HTTP verbs: GET, POST, PUT, HEAD etc...
func (app *App) Use(args ...any) Router {
var prefix string
var subApp *App
var prefixes []string
var handlers []Handler
for i := range args {
switch arg := args[i].(type) {
case string:
prefix = arg
case *App:
subApp = arg
case []string:
prefixes = arg
default:
handler, ok := toFiberHandler(arg)
if !ok {
panic(fmt.Sprintf("use: invalid handler %v\n", reflect.TypeOf(arg)))
}
handlers = append(handlers, handler)
}
}
if len(prefixes) == 0 {
prefixes = append(prefixes, prefix)
}
for _, prefix := range prefixes {
if subApp != nil {
return app.mount(prefix, subApp)
}
app.register([]string{methodUse}, prefix, nil, handlers...)
}
return appView on GitHub (pinned to a105acad6c)