hibiken/asynq · critical

asynq: multiple registrations for

Error message

asynq: multiple registrations for %s

What it means

ServeMux.Handle panics with "asynq: multiple registrations for <pattern>" when a handler was already registered for the same task pattern. Unlike net/http's mux, asynq's ServeMux does not allow overwriting; each task-type pattern may be registered exactly once, and duplicate registration is a programming error.

Solutions

  1. Remove the duplicate registration or make patterns unique per task type
  2. Centralize handler registration in one function invoked exactly once
  3. Deduplicate config-driven pattern lists before the registration loop
  4. If overwriting was intended, keep a map[string]asynq.Handler yourself and register once with the final handler

Example fix

// before
mux.Handle("email:welcome", newWelcomeHandler(cfg))
mux.Handle("email:welcome", newWelcomeHandler(cfgV2)) // panics

// after
mux.Handle("email:welcome", newWelcomeHandler(cfgV2)) // single registration only
Defensive patterns

Strategy: validation

Validate before calling

registered := map[string]bool{}
func registerOnce(mux *asynq.ServeMux, pattern string, h asynq.Handler) {
    if registered[pattern] {
        return // or log.Fatalf("duplicate registration for %s", pattern)
    }
    registered[pattern] = true
    mux.Handle(pattern, h)
}

Prevention

When it happens

Trigger: Calling mux.Handle("email:welcome", h1) then mux.Handle("email:welcome", h2); running registration code twice (e.g. both in an init and a setup function, or on hot-reload); registering the same handler for two identical constant patterns in a loop over config.

Common situations: Duplicate task-type constants in different files; duplicated setup calls during tests or server restart in-process; config listing the same task type twice.

Understand the failure class

Background: "must be a positive integer", "cannot be empty", "invalid argument": how invalid-argument errors work across open-source libraries — this error's family across 33 libraries.

Related errors


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

Appendix: source

Thrown at servemux.go:112

	}
	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)
	})
	if i == n {
		return append(es, e)
	}

View on GitHub (pinned to d135f1439b)