hibiken/asynq · critical

asynq: nil handler

Error message

asynq: nil handler

What it means

ServeMux.Handle panics with "asynq: nil handler" when the handler argument passed to Handle is nil. A registration without a concrete Handler implementation cannot dispatch tasks, so the mux rejects it immediately at registration time with a panic.

Solutions

  1. Ensure a non-nil Handler (or HandlerFunc) is passed for every registration
  2. Check factory/lookup functions so they never return nil handlers silently
  3. Guard the call: if h == nil { log.Fatal("missing handler for pattern") } before mux.Handle
  4. When wrapping handlers in middleware, verify the wrapped chain is non-nil

Example fix

// before
mux.Handle(pattern, handlers[pattern]) // may be nil

// after
if h := handlers[pattern]; h != nil {
    mux.Handle(pattern, h)
} else {
    log.Fatalf("no handler registered for %q", pattern)
}
Defensive patterns

Strategy: validation

Validate before calling

if handler == nil {
    return errors.New("cannot register nil handler for pattern " + pattern)
}
mux.Handle(pattern, handler)

Type guard

func hasHandler(h asynq.Handler) bool { return h != nil }

Prevention

When it happens

Trigger: Calling mux.Handle("task:name", nil); passing a nil Handler-typed variable (a nil *MyHandler stored in a Handler interface is caught only if the interface value itself is nil); wiring handlers from a map/slice that has a nil entry.

Common situations: Handler factories returning nil on some config path; slices of handlers built conditionally leaving nil slots; type-asserting an interface to Handler where the assertion succeeded but the value was nil.

Related errors


AI-assisted analysis of hibiken/asynq@d135f1439b (2026-09-07). Data as JSON: /api/errors/110834214442a8d0. Report an issue: GitHub.

Appendix: source

Thrown at servemux.go:109

		if strings.HasPrefix(typename, e.pattern) {
			return e.h, e.pattern
		}
	}
	return nil, ""

}

// Handle registers the handler for the given pattern.
// If a handler already exists for pattern, Handle panics.
func (mux *ServeMux) Handle(pattern string, handler Handler) {
	mux.mu.Lock()
	defer mux.mu.Unlock()

	if strings.TrimSpace(pattern) == "" {
		panic("asynq: invalid pattern")
	}
	if handler == nil {
		panic("asynq: nil handler")
	}
	if _, exist := mux.m[pattern]; exist {
		panic("asynq: multiple registrations for " + pattern)
	}

	if mux.m == nil {
		mux.m = make(map[string]muxEntry)
	}
	e := muxEntry{h: handler, pattern: pattern}
	mux.m[pattern] = e
	mux.es = appendSorted(mux.es, e)
}

func appendSorted(es []muxEntry, e muxEntry) []muxEntry {
	n := len(es)
	i := sort.Search(n, func(i int) bool {
		return len(es[i].pattern) < len(e.pattern)
	})

View on GitHub (pinned to d135f1439b)