{"record":{"id":"63bce5b11f91604d","repo":"hibiken/asynq","slug":"task-already-exists-63bce5","errorCode":null,"errorMessage":"task already exists","messagePattern":"task already exists","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/errors/errors.go","lineNumber":173,"sourceCode":"\tif !ok {\n\t\treturn Unspecified\n\t}\n\tif e.Code == Unspecified {\n\t\treturn CanonicalCode(e.Err)\n\t}\n\treturn e.Code\n}\n\n/******************************************\n    Domain Specific Error Types & Values\n*******************************************/\n\nvar (\n\t// ErrNoProcessableTask indicates that there are no tasks ready to be processed.\n\tErrNoProcessableTask = errors.New(\"no tasks are ready for processing\")\n\n\t// ErrDuplicateTask indicates that another task with the same unique key holds the uniqueness lock.\n\tErrDuplicateTask = errors.New(\"task already exists\")\n\n\t// ErrTaskIdConflict indicates that another task with the same task ID already exist\n\tErrTaskIdConflict = errors.New(\"task id conflicts with another task\")\n)\n\n// TaskNotFoundError indicates that a task with the given ID does not exist\n// in the given queue.\ntype TaskNotFoundError struct {\n\tQueue string // queue name\n\tID    string // task id\n}\n\nfunc (e *TaskNotFoundError) Error() string {\n\treturn fmt.Sprintf(\"cannot find task with id=%s in queue %q\", e.ID, e.Queue)\n}\n\n// IsTaskNotFound reports whether any error in err's chain is of type TaskNotFoundError.\nfunc IsTaskNotFound(err error) bool {","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/hibiken/asynq/blob/d135f1439bee74e989b7f9b41ecd542cc87f024a/internal/errors/errors.go#L155-L191","documentation":"Internal errors.ErrDuplicateTask (internal/errors/errors.go) indicates another task with the same unique key holds the uniqueness lock, so enqueueing was rejected by the broker. It is the internal counterpart of the public asynq.ErrDuplicateTask, which the client produces by wrapping this value.","triggerScenarios":"Enqueueing with a Unique option while a task with the identical unique key (derived from type, payload, queue, and uniqueTTL) is still locked; used by rdb enqueue paths and surfaced through EnqueueContext/EnqueueUnique/AddToGroupUnique.","commonSituations":"Same as the public variant: fast periodic producers within TTL, duplicate retries after ambiguous network failures, and multiple producers racing on the same job.","solutions":["Catch the wrapped asynq.ErrDuplicateTask at the client layer and treat as a benign skip.","Reduce uniqueTTL or wait for expiry before re-enqueueing.","Vary the payload or add a nonce so the unique key differs.","Clear the lock by deleting the unique key in Redis if you must enqueue immediately."],"exampleFix":"// before\nreturn client.Enqueue(task, asynq.Unique(ttl))\n// after\n_, err := client.Enqueue(task, asynq.Unique(ttl))\nif errors.Is(err, asynq.ErrDuplicateTask) {\n    return nil // already queued\n}\nreturn err","handlingStrategy":"type-guard","validationCode":"// Client-side duplicate guard before hitting Redis:\nif seen.Load(uniqueKey) { return ErrRecentlyEnqueued }","typeGuard":"func isDuplicate(err error) bool { return errors.Is(err, errors.ErrDuplicateTask) || errors.Is(err, asynq.ErrDuplicateTask) }","tryCatchPattern":"err := enqueueWithUnique(task, ttl)\nif isDuplicate(err) { return nil }\nif err != nil { return err }","preventionTips":["Route all unique enqueues through one helper with uniform error handling","Track unique TTLs in application metrics to tune them","Add idempotency keys to payloads so the unique key reflects true business identity"],"tags":["redis","uniqueness","internal","enqueue"],"backgroundTag":"duplicate-task","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"}