{"record":{"id":"d4b880778c50c5be","repo":"hibiken/asynq","slug":"asynq-multiple-registrations-for-s","errorCode":null,"errorMessage":"asynq: multiple registrations for %s","messagePattern":"asynq: multiple registrations for (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"servemux.go","lineNumber":112,"sourceCode":"\t}\n\treturn nil, \"\"\n\n}\n\n// Handle registers the handler for the given pattern.\n// If a handler already exists for pattern, Handle panics.\nfunc (mux *ServeMux) Handle(pattern string, handler Handler) {\n\tmux.mu.Lock()\n\tdefer mux.mu.Unlock()\n\n\tif strings.TrimSpace(pattern) == \"\" {\n\t\tpanic(\"asynq: invalid pattern\")\n\t}\n\tif handler == nil {\n\t\tpanic(\"asynq: nil handler\")\n\t}\n\tif _, exist := mux.m[pattern]; exist {\n\t\tpanic(\"asynq: multiple registrations for \" + pattern)\n\t}\n\n\tif mux.m == nil {\n\t\tmux.m = make(map[string]muxEntry)\n\t}\n\te := muxEntry{h: handler, pattern: pattern}\n\tmux.m[pattern] = e\n\tmux.es = appendSorted(mux.es, e)\n}\n\nfunc appendSorted(es []muxEntry, e muxEntry) []muxEntry {\n\tn := len(es)\n\ti := sort.Search(n, func(i int) bool {\n\t\treturn len(es[i].pattern) < len(e.pattern)\n\t})\n\tif i == n {\n\t\treturn append(es, e)\n\t}","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/hibiken/asynq/blob/d135f1439bee74e989b7f9b41ecd542cc87f024a/servemux.go#L94-L130","documentation":"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.","triggerScenarios":"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.","commonSituations":"Duplicate task-type constants in different files; duplicated setup calls during tests or server restart in-process; config listing the same task type twice.","solutions":["Remove the duplicate registration or make patterns unique per task type","Centralize handler registration in one function invoked exactly once","Deduplicate config-driven pattern lists before the registration loop","If overwriting was intended, keep a map[string]asynq.Handler yourself and register once with the final handler"],"exampleFix":"// before\nmux.Handle(\"email:welcome\", newWelcomeHandler(cfg))\nmux.Handle(\"email:welcome\", newWelcomeHandler(cfgV2)) // panics\n\n// after\nmux.Handle(\"email:welcome\", newWelcomeHandler(cfgV2)) // single registration only","handlingStrategy":"validation","validationCode":"registered := map[string]bool{}\nfunc registerOnce(mux *asynq.ServeMux, pattern string, h asynq.Handler) {\n    if registered[pattern] {\n        return // or log.Fatalf(\"duplicate registration for %s\", pattern)\n    }\n    registered[pattern] = true\n    mux.Handle(pattern, h)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Centralize all mux.Handle calls in a single setup function executed once","Ensure task-type constants are unique (greet with linters or a registry test)","Deduplicate config-driven pattern lists before registration","Be careful with init() plus explicit setup both registering the same patterns"],"tags":["panic","routing","duplicate-registration","go"],"backgroundTag":"invalid-argument","analyzedSha":"d135f1439bee74e989b7f9b41ecd542cc87f024a","analyzedAt":"2026-09-07T19:02:34.660Z","contentChangedAt":"2026-09-07T19:02:34.660Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}