{"record":{"id":"b12e05770d376532","repo":"hibiken/asynq","slug":"task-id-cannot-be-empty","errorCode":null,"errorMessage":"task ID cannot be empty","messagePattern":"task ID cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client.go","lineNumber":295,"sourceCode":"\t\ttimeout:   0, // do not set to defaultTimeout here\n\t\tdeadline:  time.Time{},\n\t\tprocessAt: time.Now(),\n\t\theaders:   make(map[string]string),\n\t}\n\tfor _, opt := range opts {\n\t\tswitch opt := opt.(type) {\n\t\tcase retryOption:\n\t\t\tres.retry = int(opt)\n\t\tcase queueOption:\n\t\t\tqname := string(opt)\n\t\t\tif err := base.ValidateQueueName(qname); err != nil {\n\t\t\t\treturn option{}, err\n\t\t\t}\n\t\t\tres.queue = qname\n\t\tcase taskIDOption:\n\t\t\tid := string(opt)\n\t\t\tif isBlank(id) {\n\t\t\t\treturn option{}, errors.New(\"task ID cannot be empty\")\n\t\t\t}\n\t\t\tres.taskID = id\n\t\tcase timeoutOption:\n\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)","sourceCodeStart":277,"sourceCodeEnd":313,"githubUrl":"https://github.com/hibiken/asynq/blob/d135f1439bee74e989b7f9b41ecd542cc87f024a/client.go#L277-L313","documentation":"A sentinel-less validation error raised in composeOptions when the taskIDOption value is blank (only whitespace). The client refuses to enqueue a task whose TaskID option carries an empty string, since an empty ID would be meaningless for conflict detection.","triggerScenarios":"Calling client.Enqueue(task, asynq.TaskID(\"\")) or TaskID(\"   \"), typically because a variable holding the ID was empty at call time.","commonSituations":"Building TaskID from a struct field or DB column that was unset/empty; string formatting that produced an empty ID; forgetting to validate user-supplied IDs before enqueueing.","solutions":["Validate the ID is non-blank before passing it to asynq.TaskID.","Skip the TaskID option entirely when no ID is available.","Fix the upstream source (struct field, DB lookup) producing the empty ID."],"exampleFix":"// before\nclient.Enqueue(task, asynq.TaskID(cfg.TaskID))\n// after\nopts := []asynq.Option{}\nif strings.TrimSpace(cfg.TaskID) != \"\" {\n    opts = append(opts, asynq.TaskID(cfg.TaskID))\n}\nclient.Enqueue(task, opts...)","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(id) == \"\" { return errors.New(\"task ID must be non-empty\") }","typeGuard":"func validTaskID(id string) bool { return strings.TrimSpace(id) != \"\" }","tryCatchPattern":"// Validation-preferred; if hit anyway:\nif err != nil && strings.Contains(err.Error(), \"task ID cannot be empty\") { /* fix caller data */ }","preventionTips":["Always trim/validate IDs sourced from external data before passing to asynq.TaskID","Skip the TaskID option when no valid ID exists","Add unit tests for enqueue paths with empty-ID inputs"],"tags":["validation","task-id","enqueue"],"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"}