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

  1. Check the panic output for the rejected type and locate that argument in your app.Use(...) call.
  2. Convert the argument to func(*fiber.Ctx) error or to a *fiber.App (for mounting) before passing.
  3. For mounting a sub-app, pass *fiber.App explicitly: app.Use("/sub", subApp).
  4. 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

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


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 app

View on GitHub (pinned to a105acad6c)