{"record":{"id":"594f7cb76c58f58d","repo":"hibiken/asynq","slug":"batch-enqueue-does-not-support-unique-tasks","errorCode":null,"errorMessage":"batch enqueue does not support unique tasks","messagePattern":"batch enqueue does not support unique tasks","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client.go","lineNumber":533,"sourceCode":"\t\t\tresults[i] = BatchEnqueueResult{Err: fmt.Errorf(\"task cannot be nil\")}\n\t\t\tcontinue\n\t\t}\n\t\tif strings.TrimSpace(task.Type()) == \"\" {\n\t\t\tresults[i] = BatchEnqueueResult{Err: fmt.Errorf(\"task typename cannot be empty\")}\n\t\t\tcontinue\n\t\t}\n\t\tmerged := append(task.opts, opts...)\n\t\topt, err := composeOptions(merged...)\n\t\tif err != nil {\n\t\t\tresults[i] = BatchEnqueueResult{Err: err}\n\t\t\tcontinue\n\t\t}\n\t\tif opt.group != \"\" {\n\t\t\tresults[i] = BatchEnqueueResult{Err: fmt.Errorf(\"batch enqueue does not support group tasks\")}\n\t\t\tcontinue\n\t\t}\n\t\tif opt.uniqueTTL > 0 {\n\t\t\tresults[i] = BatchEnqueueResult{Err: fmt.Errorf(\"batch enqueue does not support unique tasks\")}\n\t\t\tcontinue\n\t\t}\n\t\tdeadline := noDeadline\n\t\tif !opt.deadline.IsZero() {\n\t\t\tdeadline = opt.deadline\n\t\t}\n\t\ttimeout := noTimeout\n\t\tif opt.timeout != 0 {\n\t\t\ttimeout = opt.timeout\n\t\t}\n\t\tif deadline.Equal(noDeadline) && timeout == noTimeout {\n\t\t\ttimeout = defaultTimeout\n\t\t}\n\t\tmsg := &base.TaskMessage{\n\t\t\tID:        opt.taskID,\n\t\t\tType:      task.Type(),\n\t\t\tPayload:   task.Payload(),\n\t\t\tHeaders:   task.Headers(),","sourceCodeStart":515,"sourceCodeEnd":551,"githubUrl":"https://github.com/hibiken/asynq/blob/d135f1439bee74e989b7f9b41ecd542cc87f024a/client.go#L515-L551","documentation":"BatchEnqueue does not support unique tasks — tasks enqueued with asynq.Unique(ttl) or asynq.TaskID retention producing a uniqueTTL. Unique-task bookkeeping (uniqueness locks/TTL keys) is incompatible with the batch enqueue pipeline, so asynq rejects any item whose options set uniqueTTL > 0. The error is recorded per-item in BatchEnqueueResult.Err.","triggerScenarios":"Calling Client.BatchEnqueue with a task whose options include asynq.Unique(duration), e.g. deduplicating scheduled sync tasks that were also submitted in a batch.","commonSituations":"Reusing option sets across Enqueue and BatchEnqueue code paths; enabling uniqueness via a shared config helper; migrating a unique task from single enqueue into a batch submission.","solutions":["Remove the asynq.Unique(...) option for tasks submitted via BatchEnqueue, or enqueue them individually with Client.Enqueue.","Implement application-level deduplication (e.g. a Redis SETNX or DB unique column) instead of asynq uniqueness when batching.","Separate unique tasks from the batch and submit them in a second loop via Enqueue.","Inspect BatchEnqueueResult.Err for each item and re-enqueue unique tasks individually."],"exampleFix":"// before\nopt := []asynq.Option{asynq.Queue(\"sync\"), asynq.Unique(10 * time.Minute)}\nclient.BatchEnqueue(ctx, task) // rejected\n// after\nif opts.uniqueTTL > 0 {\n    _, err := client.Enqueue(task, opts...)\n} else {\n    client.BatchEnqueue(ctx, task)\n}","handlingStrategy":"validation","validationCode":"func batchableUnique(opts []asynq.Option, ttl time.Duration) bool {\n    if ttl > 0 { return false }\n    return true\n}\n// only pass asynq.Unique to single Enqueue calls","typeGuard":"func hasNoUniqueTTL(ttl time.Duration) bool { return ttl <= 0 }","tryCatchPattern":"for i, r := range results {\n    if r.Err != nil && strings.Contains(r.Err.Error(), \"does not support unique tasks\") {\n        // re-enqueue individually with asynq.Unique\n    }\n}","preventionTips":["Route unique tasks through Client.Enqueue, never BatchEnqueue.","Use application-level dedup keys when batching.","Keep uniqueness options out of shared option-slice helpers.","Check BatchEnqueueResult.Err per item."],"tags":["go","asynq","batch-enqueue","unique-tasks"],"backgroundTag":"unsupported-operation","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"}