gofiber/fiber · critical

fiber: Config.RegexHandler must be a non-nil function

Error message

fiber: Config.RegexHandler must be a non-nil function

What it means

validateRegexHandler runs at app initialization when Config.RegexHandler is set. It rejects values that are not reflect.Func or that are nil functions. This catches misconfiguration before any route is registered.

Solutions

  1. Leave Config.RegexHandler unset to use the default regexp.MustCompile.
  2. Pass a function value: Config.RegexHandler: regexp.MustCompile.
  3. If loading dynamically, type-check it is a non-nil func before assignment.

Example fix

// before
app := fiber.New(fiber.Config{RegexHandler: nil})
// or
app := fiber.New(fiber.Config{RegexHandler: regexp.MustCompile(`\d+`)}) // a Regexp, not a func

// after
app := fiber.New() // use default
// or
app := fiber.New(fiber.Config{RegexHandler: regexp.MustCompile}) // the function itself
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate RegexHandler is a non-nil function before passing to Config
func validateRegexHandlerTyped(h any) error {
    if h == nil { return errors.New("nil handler") }
    hv := reflect.ValueOf(h)
    if hv.Kind() != reflect.Func { return errors.New("not a function") }
    if hv.IsNil() { return errors.New("nil function") }
    return nil
}

Type guard

func isNonNilFunc(v any) bool {
    if v == nil { return false }
    rv := reflect.ValueOf(v)
    return rv.Kind() == reflect.Func && !rv.IsNil()
}

Prevention

When it happens

Trigger: Setting Config.RegexHandler to nil (explicitly), to a non-function value, or to a func variable that was declared but never assigned.

Common situations: Loading the handler from config/plugin and getting nil; passing regexp.MustCompile (correct) vs. passing a *regexp.Regexp instance (wrong, not a function); refactor changing the field type.

Related errors


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

Appendix: source

Thrown at constraint.go:58

	result := reflect.ValueOf(handler).Call([]reflect.Value{reflect.ValueOf(pattern)})
	matcher, ok := result[0].Interface().(regexMatcher)
	if !ok {
		panic("fiber: Config.RegexHandler return type must support MatchString(string) bool")
	}
	if isNilRegexMatcher(matcher) {
		panic("fiber: Config.RegexHandler must not return nil")
	}
	return matcher
}

func validateRegexHandler(handler any) any {
	if handler == nil {
		return regexp.MustCompile
	}
	handlerValue := reflect.ValueOf(handler)
	handlerType := handlerValue.Type()
	if handlerType.Kind() != reflect.Func || handlerValue.IsNil() {
		panic("fiber: Config.RegexHandler must be a non-nil function")
	}
	if handlerType.NumIn() != 1 || handlerType.In(0) != stringType || handlerType.NumOut() != 1 {
		panic("fiber: Config.RegexHandler must have signature func(string) T")
	}
	if !handlerType.Out(0).Implements(regexMatcherType) {
		panic("fiber: Config.RegexHandler return type must support MatchString(string) bool")
	}
	return handler
}

// ConstraintHandler is the interface that all constraints must implement.
// Built-in and custom constraints are treated uniformly through this interface.
type ConstraintHandler interface {
	// Name returns the constraint identifier used in route patterns (e.g. "int", "minLen", "regex").
	Name() string

	// Execute validates a request parameter value against the constraint.
	// param is the request parameter value to check.

View on GitHub (pinned to a105acad6c)