{"record":{"id":"e6f9f39173e45169","repo":"hibiken/asynq","slug":"w-q","errorCode":null,"errorMessage":"%w %q","messagePattern":"%w %q","errorType":"exception","errorClass":"ErrHandlerNotFound","httpStatus":null,"severity":"error","filePath":"servemux.go","lineNumber":156,"sourceCode":"// HandleFunc registers the handler function for the given pattern.\nfunc (mux *ServeMux) HandleFunc(pattern string, handler func(context.Context, *Task) error) {\n\tif handler == nil {\n\t\tpanic(\"asynq: nil handler\")\n\t}\n\tmux.Handle(pattern, HandlerFunc(handler))\n}\n\n// Use appends a MiddlewareFunc to the chain.\n// Middlewares are executed in the order that they are applied to the ServeMux.\nfunc (mux *ServeMux) Use(mws ...MiddlewareFunc) {\n\tmux.mu.Lock()\n\tdefer mux.mu.Unlock()\n\tmux.mws = append(mux.mws, mws...)\n}\n\n// NotFound returns an error indicating that the handler was not found for the given task.\nfunc NotFound(ctx context.Context, task *Task) error {\n\treturn fmt.Errorf(\"%w %q\", ErrHandlerNotFound, task.Type())\n}\n\n// NotFoundHandler returns a simple task handler that returns a “not found“ error.\nfunc NotFoundHandler() Handler { return HandlerFunc(NotFound) }\n","sourceCodeStart":138,"sourceCodeEnd":161,"githubUrl":"https://github.com/hibiken/asynq/blob/d135f1439bee74e989b7f9b41ecd542cc87f024a/servemux.go#L138-L161","documentation":"NotFound is the handler asynq uses when a task's type has no registered handler in a ServeMux. It wraps ErrHandlerNotFound and includes the task type so developers can see which type is unregistered. The server will record this error and the task goes through normal error/retry handling.","triggerScenarios":"Enqueuing/processing a task whose Type string was never registered via mux.HandleFunc/mux.Handle — typos in type names, task types added by newer producers but not by the consumer, or type strings built dynamically.","commonSituations":"Producer/consumer version skew where the producer enqueues a new task type the old worker doesn't know; refactoring renamed task constants on one side only; sharing type strings as raw literals instead of constants.","solutions":["Register the missing type on the ServeMux: mux.HandleFunc(task.Type(), handler)","Fix the type-name mismatch — use shared constants like \"email:welcome\" between producer and consumer","If unhandled types are expected, mount mux.Use(asynq.NotFoundHandler()) behavior deliberately or log-and-ack via a custom middleware"],"exampleFix":"// before\nmux.HandleFunc(\"email:welcome\", welcomeHandler) // task type is \"email:remind\"\n// after\nmux.HandleFunc(\"email:welcome\", welcomeHandler)\nmux.HandleFunc(\"email:remind\", remindHandler)","handlingStrategy":"try-catch","validationCode":"registered := map[string]bool{\n    \"email:welcome\": true,\n    \"email:remind\": true,\n}\nif !registered[t.Type()] {\n    log.Printf(\"warning: task type %q has no handler registered\", t.Type())\n}","typeGuard":"func hasHandler(mux *asynq.ServeMux, taskType string) bool {\n    return knownTypes[taskType]\n}","tryCatchPattern":"if errors.Is(err, asynq.ErrHandlerNotFound) {\n    log.Printf(\"unregistered task type %q; dropping or routing to DLQ\", taskType)\n    return nil // or forward for inspection\n}","preventionTips":["Define all task type strings as shared constants imported by producer and consumer","Add a startup test that enqueues one task of every type against the mux","Keep producer and worker deployments in sync when adding new task types"],"tags":["asynq","handler","servemux","not-found"],"backgroundTag":"resource-not-found","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"}