gofiber/fiber · error

nil handler in route

Error message

nil handler in route: %s

What it means

register iterates every handler passed to a route registration and panics if any is nil. A nil handler would later panic inside the router when invoked, so this guard surfaces the mistake at startup with the offending path. This is distinct from the "missing handler" check: here handlers were provided, but one of them is a nil function value.

Solutions

  1. Ensure every handler/middleware value is non-nil before passing it to a registration method.
  2. If a middleware is optional, conditionally append it rather than inserting nil, or substitute a no-op handler.
  3. Lint for nil-typed handler variables in route-building code.

Example fix

// before
var auth fiber.Handler // nil when not configured
app.Get("/secret", auth, handler) // panics: nil handler

// after
app.Get("/secret", handler)
if auth != nil {
    app.Get("/secret", auth, handler)
}
Defensive patterns

Strategy: type-guard

Validate before calling

func cleanHandlers(handlers ...fiber.Handler) []fiber.Handler {
    out := make([]fiber.Handler, 0, len(handlers))
    for _, h := range handlers {
        if h != nil { out = append(out, h) }
    }
    return out
}
// app.Get("/x", cleanHandlers(h1, h2)...)

Type guard

func noNilHandlers(handlers []fiber.Handler) bool {
    for _, h := range handlers { if h == nil { return false } }
    return true
}

Prevention

When it happens

Trigger: app.Get("/x", h1, nil, h3) where a handler variable was never assigned; passing a nil element from a handler slice; a middleware factory that returned nil on a misconfiguration.

Common situations: A handler variable conditionally assigned that stayed nil; a slice of middleware where one entry was nil; refactoring that left a placeholder nil in a chain; appending middleware that was supposed to be constructed but was not.

Related errors


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

Appendix: source

Thrown at router.go:1003

			continue
		}

		app.stack[headIndex] = append(headStack[:i], headStack[i+1:]...)
		app.hasRoutesRefreshed = true
		atomic.AddUint32(&app.handlersCount, ^uint32(len(headRoute.Handlers)-1)) //nolint:gosec // G115 - handler count is always small
		return
	}
}

func (app *App) register(methods []string, pathRaw string, group *Group, handlers ...Handler) {
	// A regular route requires at least one ctx handler
	if len(handlers) == 0 && group == nil {
		panic(fmt.Sprintf("missing handler/middleware in route: %s\n", pathRaw))
	}
	// No nil handlers allowed
	for _, h := range handlers {
		if h == nil {
			panic(fmt.Sprintf("nil handler in route: %s\n", pathRaw))
		}
	}

	// Precompute path normalization ONCE
	if pathRaw == "" {
		pathRaw = "/"
	}
	if pathRaw[0] != '/' {
		pathRaw = "/" + pathRaw
	}
	pathPretty := pathRaw
	if !app.config.CaseSensitive {
		pathPretty = utilsstrings.ToLower(pathPretty)
	}
	if !app.config.StrictRouting && len(pathPretty) > 1 {
		pathPretty = utils.TrimRight(pathPretty, '/')
	}
	pathClean := RemoveEscapeChar(pathPretty)

View on GitHub (pinned to a105acad6c)