gofiber/fiber · critical

route handler 'fn' cannot be nil

Error message

route handler 'fn' cannot be nil

What it means

App.Route(prefix, fn) requires a non-nil function that registers routes on the sub-router; calling it with a nil fn panics immediately. The guard prevents a silent no-op route group, which would be a confusing runtime defect.

Solutions

  1. Ensure the function passed to Route is a non-nil func(router fiber.Router).
  2. If routes are optional, guard the call: if register != nil { app.Route("/api", register) }.
  3. Load modules eagerly and fail loudly if a route registrar is missing rather than passing nil.

Example fix

// before
app.Route("/api", moduleLoader.Get("api")) // returns nil when missing

// after
reg := moduleLoader.Get("api")
if reg == nil { log.Fatal("api route registrar missing") }
app.Route("/api", reg)
Defensive patterns

Strategy: validation

Validate before calling

// Guard Route against nil registrars
func routeIf(app *fiber.App, prefix string, fn func(fiber.Router)) {
    if fn == nil { return }
    app.Route(prefix, fn)
}

Type guard

func isRouteFn(v any) bool {
    f, ok := v.(func(fiber.Router))
    return ok && f != nil
}

Prevention

When it happens

Trigger: Passing a nil function as the second argument: app.Route("/api", nil). Common when the route-registration function is conditionally assigned or fetched from a map and ends up nil.

Common situations: Plugin/module loader returning nil for a missing module; conditional route setup where the closure variable was never assigned; refactor leaving a dangling nil.

Related errors


AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11). Data as JSON: /api/errors/f7ba542335cb6250. Report an issue: GitHub.

Appendix: source

Thrown at app.go:1201

	}
}

// RouteChain creates a Registering instance that lets you declare a stack of
// handlers for the same route. Handlers defined via the returned Register are
// scoped to the provided path.
func (app *App) RouteChain(path string) Register {
	// Create new route
	route := &Registering{app: app, path: path}

	return route
}

// Route is used to define routes with a common prefix inside the supplied
// function. It mirrors the legacy helper and reuses the Group method to create
// a sub-router.
func (app *App) Route(prefix string, fn func(router Router), name ...string) Router {
	if fn == nil {
		panic("route handler 'fn' cannot be nil")
	}
	// Create new group
	group := app.Group(prefix)
	if len(name) > 0 {
		group.Name(name[0])
	}

	// Define routes
	fn(group)

	return group
}

// Error makes it compatible with the `error` interface.
func (e *Error) Error() string {
	return e.Message
}

View on GitHub (pinned to a105acad6c)