hibiken/asynq · error

batch enqueue does not support unique tasks

Error message

batch enqueue does not support unique tasks

What it means

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.

Solutions

  1. Remove the asynq.Unique(...) option for tasks submitted via BatchEnqueue, or enqueue them individually with Client.Enqueue.
  2. Implement application-level deduplication (e.g. a Redis SETNX or DB unique column) instead of asynq uniqueness when batching.
  3. Separate unique tasks from the batch and submit them in a second loop via Enqueue.
  4. Inspect BatchEnqueueResult.Err for each item and re-enqueue unique tasks individually.

Example fix

// before
opt := []asynq.Option{asynq.Queue("sync"), asynq.Unique(10 * time.Minute)}
client.BatchEnqueue(ctx, task) // rejected
// after
if opts.uniqueTTL > 0 {
    _, err := client.Enqueue(task, opts...)
} else {
    client.BatchEnqueue(ctx, task)
}
Defensive patterns

Strategy: validation

Validate before calling

func batchableUnique(opts []asynq.Option, ttl time.Duration) bool {
    if ttl > 0 { return false }
    return true
}
// only pass asynq.Unique to single Enqueue calls

Type guard

func hasNoUniqueTTL(ttl time.Duration) bool { return ttl <= 0 }

Try / catch

for i, r := range results {
    if r.Err != nil && strings.Contains(r.Err.Error(), "does not support unique tasks") {
        // re-enqueue individually with asynq.Unique
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of hibiken/asynq@d135f1439b (2026-09-07). Data as JSON: /api/errors/594f7cb76c58f58d. Report an issue: GitHub.

Appendix: source

Thrown at client.go:533

			results[i] = BatchEnqueueResult{Err: fmt.Errorf("task cannot be nil")}
			continue
		}
		if strings.TrimSpace(task.Type()) == "" {
			results[i] = BatchEnqueueResult{Err: fmt.Errorf("task typename cannot be empty")}
			continue
		}
		merged := append(task.opts, opts...)
		opt, err := composeOptions(merged...)
		if err != nil {
			results[i] = BatchEnqueueResult{Err: err}
			continue
		}
		if opt.group != "" {
			results[i] = BatchEnqueueResult{Err: fmt.Errorf("batch enqueue does not support group tasks")}
			continue
		}
		if opt.uniqueTTL > 0 {
			results[i] = BatchEnqueueResult{Err: fmt.Errorf("batch enqueue does not support unique tasks")}
			continue
		}
		deadline := noDeadline
		if !opt.deadline.IsZero() {
			deadline = opt.deadline
		}
		timeout := noTimeout
		if opt.timeout != 0 {
			timeout = opt.timeout
		}
		if deadline.Equal(noDeadline) && timeout == noTimeout {
			timeout = defaultTimeout
		}
		msg := &base.TaskMessage{
			ID:        opt.taskID,
			Type:      task.Type(),
			Payload:   task.Payload(),
			Headers:   task.Headers(),

View on GitHub (pinned to d135f1439b)