hibiken/asynq · error
handler not found for task
Error message
handler not found for task
What it means
ErrHandlerNotFound is a sentinel error indicating that no task handler was registered for the given task type in a ServeMux. The library throws it when a task is dequeued/processed but its type does not match any registered pattern; NotFound wraps the sentinel with the task's quoted type name. Callers can match with errors.Is to distinguish this from handler failures.
Solutions
- Register the missing handler for the task type shown in the error via mux.Handle/HandleFunc before calling srv.Run/Start
- Compare the quoted type in the error against the string passed to NewTask at enqueue time and fix any mismatch
- Use a custom NotFoundHandler / mux.Handle with a catch-all pattern to log unexpected task types during development
Example fix
// before
mux.HandleFunc("email:welcome", handleWelcomeEmail)
// task enqueued as asynq.NewTask("email:wellcome", payload)
// after
mux.HandleFunc("email:welcome", handleWelcomeEmail)
// enqueue with matching type:
client.Enqueue(asynq.NewTask("email:welcome", payload)) Defensive patterns
Strategy: try-catch
Validate before calling
if _, ok := mux.(*asynq.ServeMux); ok {
// keep a registry of task types and assert before enqueue
if !registeredTypes[taskType] {
return fmt.Errorf("no handler registered for %q", taskType)
}
} Try / catch
err := task.ProcessTask(ctx, t)
if err != nil && errors.Is(err, asynq.ErrHandlerNotFound) {
log.Printf("no handler for task type %q", t.Type())
return asynq.SkipRetry // or DLQ handling
} Prevention
- Define task type strings as shared constants used by both enqueue and mux registration
- Add a startup test that enqueues each task type against the mux and asserts no ErrHandlerNotFound
- Register all handlers before calling srv.Run/Start
When it happens
Trigger: Processing (or inspecting) a task whose Type() does not match any pattern registered via ServeMux.Handle/HandleFunc; also returned by ServeMux.NotFoundHandler when invoked. Error is constructed by NotFound() at servemux.go:156.
Common situations: Typo in the pattern string vs the task type used at enqueue time; handler registered after the server started processing (race on startup); refactoring task type constants without updating both enqueue and mux registration sides; forgetting to register a handler for tasks enqueued by another service.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- task id conflicts with another task
- testutil: redis is down
- skip retry for the task
- revoke task
- asynq: task lease expired
AI-assisted analysis of hibiken/asynq@d135f1439b (2026-09-07).
Data as JSON: /api/errors/ac360f98bcde2728.
Report an issue: GitHub.
Appendix: source
Thrown at servemux.go:17
// Copyright 2020 Kentaro Hibino. All rights reserved.
// Use of this source code is governed by a MIT license
// that can be found in the LICENSE file.
package asynq
import (
"context"
"errors"
"fmt"
"sort"
"strings"
"sync"
)
// ErrHandlerNotFound indicates that no task handler was found for a given pattern.
var ErrHandlerNotFound = errors.New("handler not found for task")
// ServeMux is a multiplexer for asynchronous tasks.
// It matches the type of each task against a list of registered patterns
// and calls the handler for the pattern that most closely matches the
// task's type name.
//
// Longer patterns take precedence over shorter ones, so that if there are
// handlers registered for both "images" and "images:thumbnails",
// the latter handler will be called for tasks with a type name beginning with
// "images:thumbnails" and the former will receive tasks with type name beginning
// with "images".
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
es []muxEntry // slice of entries sorted from longest to shortest.
mws []MiddlewareFunc
}
View on GitHub (pinned to d135f1439b)