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
- Remove the asynq.Group(...) option for tasks submitted through BatchEnqueue, or enqueue group tasks individually with Client.Enqueue.
- Split the batch: enqueue group tasks one-by-one and only batch-enqueue non-group tasks.
- Make the enqueue helper configurable so group tasks bypass the batch path.
- 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
- Keep group tasks out of shared batch-enqueue helpers.
- Document that BatchEnqueue forbids group and unique options.
- Audit option sets when introducing batch enqueue.
- Handle per-item errors instead of assuming whole-batch success.
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
- batch enqueue does not support unique tasks
- redis connection is shared so the Inspector can't be closed…
- asynq
- asynq: unsupported log level
- asynq: server cannot run with nil handler
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)