hibiken/asynq · error
task id conflicts with another task
Error message
task id conflicts with another task
What it means
ErrTaskIdConflict indicates that another task with the same task ID already exists in the queue. Asynq lets callers supply an explicit task ID; the broker enforces that IDs are unique among pending/scheduled tasks by detecting a zero-return from the underlying Redis operation (internal/rdb/rdb.go:137 maps n==0 to this error via errors.AlreadyExists). It is returned by the enqueue-family APIs: EnqueueContext, Enqueue, EnqueueUnique, AddToGroup, AddToGroupUnique, and Schedule.
Solutions
- Don't set an explicit ID (omit the WithTaskID option) and let asynq generate a unique one, unless you specifically need deterministic IDs.
- Before enqueueing, check whether a task with that ID already exists (e.g. via inspector.ListPendingTasks / inspector.GetTaskInfo) and skip or update instead of enqueueing.
- If the ID conflict is expected, treat it as success/idempotency: check errors.Is(err, asynq.ErrTaskIdConflict) and continue.
- Clear the conflicting old task (delete/ archive it via Inspector) before enqueueing with the same ID.
Example fix
// before
if err := client.Enqueue(task, asynq.WithTaskID(orderID)); err != nil {
return err // fails with ErrTaskIdConflict on re-runs
}
// after
if err := client.Enqueue(task, asynq.WithTaskID(orderID)); err != nil {
if errors.Is(err, asynq.ErrTaskIdConflict) {
return nil // task with this ID already queued; idempotent no-op
}
return err
} Defensive patterns
Strategy: try-catch
Validate before calling
info := inspector.GetTaskInfo(queue, taskID); if info != nil && info.State == asynq.TaskStatePending { /* skip enqueue or use different ID */ } Type guard
func isTaskIDConflict(err error) bool { return errors.Is(err, asynq.ErrTaskIdConflict) } Try / catch
if err := client.Enqueue(t, asynq.WithTaskID(id)); err != nil {
if errors.Is(err, asynq.ErrTaskIdConflict) {
return nil // already enqueued; idempotent
}
return fmt.Errorf("enqueue %s: %w", id, err)
} Prevention
- Avoid WithTaskID unless deterministic IDs are a hard requirement.
- Derive task IDs from truly unique keys (UUIDs) when explicit IDs are needed.
- Check for existing tasks via Inspector before re-enqueueing with a fixed ID.
- Treat ErrTaskIdConflict as a success signal in idempotent enqueue paths.
When it happens
Trigger: Calling Enqueue/EnqueueUnique/Schedule/AddToGroup/AddToGroupUnique with a task whose Option (WithTaskID) sets an ID that already matches an existing pending, scheduled, or aggregated task in the same queue.
Common situations: Re-enqueuing the same task after a failure without changing or clearing the explicit ID; client code deriving task IDs from user-supplied keys (order IDs, request IDs) that can repeat; retrying an enqueue after a network blip where the first attempt actually succeeded; idempotency schemes that treat explicit IDs like unique keys without realizing uniqueness only applies to pending tasks.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- task already exists
- task already exists
- testutil: redis is down
- asynq: could not parse redis uri
- asynq: unsupported uri scheme
AI-assisted analysis of hibiken/asynq@d135f1439b (2026-09-07).
Data as JSON: /api/errors/812eda3a5fffafb5.
Report an issue: GitHub.
Appendix: source
Thrown at internal/errors/errors.go:176
if e.Code == Unspecified {
return CanonicalCode(e.Err)
}
return e.Code
}
/******************************************
Domain Specific Error Types & Values
*******************************************/
var (
// ErrNoProcessableTask indicates that there are no tasks ready to be processed.
ErrNoProcessableTask = errors.New("no tasks are ready for processing")
// ErrDuplicateTask indicates that another task with the same unique key holds the uniqueness lock.
ErrDuplicateTask = errors.New("task already exists")
// ErrTaskIdConflict indicates that another task with the same task ID already exist
ErrTaskIdConflict = errors.New("task id conflicts with another task")
)
// TaskNotFoundError indicates that a task with the given ID does not exist
// in the given queue.
type TaskNotFoundError struct {
Queue string // queue name
ID string // task id
}
func (e *TaskNotFoundError) Error() string {
return fmt.Sprintf("cannot find task with id=%s in queue %q", e.ID, e.Queue)
}
// IsTaskNotFound reports whether any error in err's chain is of type TaskNotFoundError.
func IsTaskNotFound(err error) bool {
var target *TaskNotFoundError
return As(err, &target)
}View on GitHub (pinned to d135f1439b)