hibiken/asynq · error

batch enqueue does not support group tasks

Error message

batch enqueue does not support group tasks

What it means

BatchEnqueue does not allow tasks enqueued with a group option (asynq.Queue with Group used for aggregation). Because batch enqueue bypasses per-task group routing, asynq rejects any item whose composed options contain a non-empty group. The error is recorded per-item in BatchEnqueueResult.Err.

Solutions

  1. Remove the asynq.Group(...) option for tasks submitted through BatchEnqueue, or enqueue group tasks individually with Client.Enqueue.
  2. Split the batch: enqueue group tasks one-by-one and only batch-enqueue non-group tasks.
  3. Make the enqueue helper configurable so group tasks bypass the batch path.
  4. Check each BatchEnqueueResult.Err to identify and re-enqueue rejected items individually.

Example fix

// before
opt := []asynq.Option{asynq.Queue("events"), asynq.Group("events:2024-01")}
client.BatchEnqueue(ctx, task) // rejected
// after
if opts.group != "" {
    _, err := client.Enqueue(task, opts...)
} else {
    client.BatchEnqueue(ctx, task)
}
Defensive patterns

Strategy: validation

Validate before calling

func batchable(opts []asynq.Option) bool {
    o := asynq.ComposeOptions(opts...)
    return o.GetGroup() == ""
}

Type guard

func isGroupFreeTask(opts []asynq.Option) bool { return asynq.ComposeOptions(opts...).GetGroup() == "" }

Try / catch

for i, r := range results {
    if r.Err != nil && strings.Contains(r.Err.Error(), "does not support group tasks") {
        // fall back to single enqueue
    }
}

Prevention

When it happens

Trigger: Calling Client.BatchEnqueue with tasks whose options include asynq.Group("some-group") — e.g. batch-submitting aggregation tasks that were configured for group-based aggregation on a Redis cluster.

Common situations: Mixing group/aggregation tasks into a shared batch-enqueue helper; enabling group aggregation via a config flag and passing the option unconditionally; migrating from single Enqueue to BatchEnqueue without auditing per-task options.

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/f4ae6327bd167b5b. Report an issue: GitHub.

Appendix: source

Thrown at client.go:529

	itemMetas := make([]itemMeta, 0, len(tasks))

	for i, task := range tasks {
		if task == nil {
			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{

View on GitHub (pinned to d135f1439b)