{"record":{"id":"f886c941339101b9","repo":"hibiken/asynq","slug":"group-key-cannot-be-empty","errorCode":null,"errorMessage":"group key cannot be empty","messagePattern":"group key cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client.go","lineNumber":317,"sourceCode":"\t\t\tres.timeout = time.Duration(opt)\n\t\tcase deadlineOption:\n\t\t\tres.deadline = time.Time(opt)\n\t\tcase uniqueOption:\n\t\t\tttl := time.Duration(opt)\n\t\t\tif ttl < 1*time.Second {\n\t\t\t\treturn option{}, errors.New(\"Unique TTL cannot be less than 1s\")\n\t\t\t}\n\t\t\tres.uniqueTTL = ttl\n\t\tcase processAtOption:\n\t\t\tres.processAt = time.Time(opt)\n\t\tcase processInOption:\n\t\t\tres.processAt = time.Now().Add(time.Duration(opt))\n\t\tcase retentionOption:\n\t\t\tres.retention = time.Duration(opt)\n\t\tcase groupOption:\n\t\t\tkey := string(opt)\n\t\t\tif isBlank(key) {\n\t\t\t\treturn option{}, errors.New(\"group key cannot be empty\")\n\t\t\t}\n\t\t\tres.group = key\n\t\tcase headerOption:\n\t\t\tkey, value := opt[0], opt[1]\n\t\t\tres.headers[key] = value\n\t\tdefault:\n\t\t\t// ignore unexpected option\n\t\t}\n\t}\n\treturn res, nil\n}\n\n// isBlank returns true if the given s is empty or consist of all whitespaces.\nfunc isBlank(s string) bool {\n\treturn strings.TrimSpace(s) == \"\"\n}\n\nconst (","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/hibiken/asynq/blob/d135f1439bee74e989b7f9b41ecd542cc87f024a/client.go#L299-L335","documentation":"Validation guard in composeOptions: the WithGroup option was constructed with a blank (empty or whitespace-only) group key. Aggregation requires a non-empty group key to route the task into a group, so enqueueing fails immediately instead of creating an invalid group.","triggerScenarios":"Calling client.Enqueue(task, asynq.Group(\"\")) or Group(\"  \"), typically when the group key derives from an empty variable (tenant ID, event name).","commonSituations":"Aggregation key sourced from an unset request field; template/config producing empty keys; forgetting that group keys must also satisfy the aggregator's GroupMaxDelay/size settings.","solutions":["Validate the group key is non-blank before enqueueing.","Fall back to enqueueing without the Group option, or use a default key.","Fix the upstream data source producing the empty key."],"exampleFix":"// before\nclient.Enqueue(task, asynq.Group(tenant.Name))\n// after\nif strings.TrimSpace(tenant.Name) == \"\" {\n    return errors.New(\"cannot enqueue: empty group key\")\n}\nclient.Enqueue(task, asynq.Group(tenant.Name))","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(groupKey) == \"\" { return errors.New(\"group key must be non-empty\") }","typeGuard":"func validGroupKey(k string) bool { return strings.TrimSpace(k) != \"\" }","tryCatchPattern":"// Prefer validation; on hit, fall back to non-grouped enqueue:\nif strings.Contains(err.Error(), \"group key cannot be empty\") { client.Enqueue(task) }","preventionTips":["Validate aggregation keys derived from request/tenant data at the boundary","Provide a default group key fallback","Test aggregation enqueue paths with empty-key inputs"],"tags":["validation","aggregation","group"],"backgroundTag":"empty-required-field","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"}