hibiken/asynq · error
PeriodicTaskConfig.Task cannot be nil
Error message
PeriodicTaskConfig.Task cannot be nil
What it means
validatePeriodicTaskConfig returns this error when a PeriodicTaskConfig has a nil Task field. A config without a Task has nothing to enqueue, so the sync loop rejects it. Raised during initialSync/sync for each offending provider-supplied config.
Solutions
- Always populate Task with a non-nil *asynq.Task in every config
- Add a pre-return validation loop in the provider mirroring validatePeriodicTaskConfig
- Fail fast in the provider when a spec cannot be mapped to a Task
Example fix
// before
return []*asynq.PeriodicTaskConfig{
{Cronspec: "0 6 * * *", Options: []asynq.Option{}}, // Task missing
}, nil
// after
return []*asynq.PeriodicTaskConfig{
{Task: asynq.NewTask("report:generate", nil), Cronspec: "0 6 * * *"},
}, nil Defensive patterns
Strategy: validation
Validate before calling
for i, c := range cfgs {
if c != nil && c.Task == nil {
return fmt.Errorf("config %d (%s) has nil Task", i, c.Cronspec)
}
} Type guard
func hasTask(c *asynq.PeriodicTaskConfig) bool { return c != nil && c.Task != nil } Try / catch
if err := mgr.Run(); err != nil {
if strings.Contains(err.Error(), "PeriodicTaskConfig.Task cannot be nil") {
// fix provider to always set Task
}
return err
} Prevention
- Construct every PeriodicTaskConfig with asynq.NewTask(...)
- Add a validate loop in the provider mirroring library checks
- Cover config construction with table-driven tests
- Reject incomplete specs at the persistence layer
When it happens
Trigger: A PeriodicTaskConfigProvider returns a config where only Cronspec (and maybe Options) is set but the Task field is left nil.
Common situations: Constructing configs from persisted spec strings and forgetting to rebuild the asynq.Task; conditional task construction that yields nil on a code path; copy-paste of a config literal missing the Task line.
Related errors
- PeriodicTaskConfig cannot be nil
- PeriodicTaskConfigProvider cannot be nil
- task ID cannot be empty
- Unique TTL cannot be less than 1s
- group key cannot be empty
AI-assisted analysis of hibiken/asynq@d135f1439b (2026-09-07).
Data as JSON: /api/errors/dc526e6037088bda.
Report an issue: GitHub.
Appendix: source
Thrown at periodic_task_manager.go:108
func (c *PeriodicTaskConfig) hash() string {
h := sha256.New()
_, _ = h.Write([]byte(c.Cronspec))
_, _ = h.Write([]byte(c.Task.Type()))
h.Write(c.Task.Payload())
opts := stringifyOptions(c.Opts)
sort.Strings(opts)
for _, opt := range opts {
_, _ = h.Write([]byte(opt))
}
return fmt.Sprintf("%x", h.Sum(nil))
}
func validatePeriodicTaskConfig(c *PeriodicTaskConfig) error {
if c == nil {
return fmt.Errorf("PeriodicTaskConfig cannot be nil")
}
if c.Task == nil {
return fmt.Errorf("PeriodicTaskConfig.Task cannot be nil")
}
if c.Cronspec == "" {
return fmt.Errorf("PeriodicTaskConfig.Cronspec cannot be empty")
}
return nil
}
// Start starts a scheduler and background goroutine to sync the scheduler with the configs
// returned by the provider.
//
// Start returns any error encountered at start up time.
func (mgr *PeriodicTaskManager) Start() error {
if mgr.s == nil || mgr.p == nil {
panic("asynq: cannot start uninitialized PeriodicTaskManager; use NewPeriodicTaskManager to initialize")
}
if err := mgr.initialSync(); err != nil {
return fmt.Errorf("asynq: %w", err)
}View on GitHub (pinned to d135f1439b)