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

  1. Register the missing handler for the task type shown in the error via mux.Handle/HandleFunc before calling srv.Run/Start
  2. Compare the quoted type in the error against the string passed to NewTask at enqueue time and fix any mismatch
  3. 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

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


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)