gofiber/fiber · error

route handler 'fn' cannot be nil

Error message

route handler 'fn' cannot be nil

What it means

domainRouter.Route(prefix, fn, name...) requires a non-nil callback fn that defines nested routes inside the group. Passing nil is a programming error with no valid use, so fiber panics immediately rather than silently creating an empty group. The guard runs before any group is constructed.

Solutions

  1. Ensure the callback is always a non-nil func literal: d.Route(prefix, func(r fiber.Router) { ... }).
  2. If the callback may legitimately be absent, guard the call site: if fn != nil { d.Route(prefix, fn) }.
  3. Initialize route-builder variables to a no-op func(fiber.Router) instead of nil when their assignment is conditional.

Example fix

// before
var fn func(router Router)
if registerV1 { fn = buildV1 }
d.Route("/v1", fn)
// after
if fn != nil {
    d.Route("/v1", fn)
}
Defensive patterns

Strategy: validation

Validate before calling

if routeBuilder == nil {
    return errors.New("route builder callback must not be nil")
}
d.Route("/v1", routeBuilder)

Try / catch

defer func() {
    if r := recover(); r != nil {
        log.Fatalf("Route fn nil: %v", r)
    }
}()
d.Route("/v1", fn)

Prevention

When it happens

Trigger: Calling d.Route("/v1", nil) on a domain router, typically because the callback variable was never assigned, was conditionally set to nil, or was passed by mistake from a higher-level wrapper.

Common situations: Conditionally building routes (var fn func(fiber.Router); if cond { fn = ... }; d.Route(prefix, fn)) and hitting the false branch; refactoring that leaves an unresolved symbol; calling Route inside a loop where one iteration has no routes to register.

Related errors


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

Appendix: source

Thrown at domain.go:594

		app:     d.app,
		group:   newGrp,
		matcher: d.matcher,
	}
}

// RouteChain creates a Registering instance for the domain router.
func (d *domainRouter) RouteChain(path string) Register {
	return &domainRegistering{
		domain: d,
		path:   d.registerPath(path),
	}
}

// Route defines routes with a common prefix inside the supplied function,
// scoped to the domain pattern.
func (d *domainRouter) Route(prefix string, fn func(router Router), name ...string) Router {
	if fn == nil {
		panic("route handler 'fn' cannot be nil")
	}

	group := d.Group(prefix)
	if len(name) > 0 {
		group.Name(name[0])
	}

	fn(group)

	return group
}

// Name assigns a name to the most recently registered route.
// When the domain router was created from a Group, this delegates to the
// group's Name method so that group name prefixes are applied correctly.
func (d *domainRouter) Name(name string) Router {
	if d.group != nil {
		d.group.Name(name)

View on GitHub (pinned to a105acad6c)