hibiken/asynq · error

PeriodicTaskConfig cannot be nil

Error message

PeriodicTaskConfig cannot be nil

What it means

validatePeriodicTaskConfig returns this error when a config entry supplied by the PeriodicTaskConfigProvider is nil. The sync loop (initialSync/sync) validates every provider-returned config before enqueuing, and a nil pointer cannot describe a task. It surfaces during the manager's periodic sync rather than at construction.

Solutions

  1. Filter nil entries out of the slice in the provider before returning it
  2. Return an explicit error from the provider when data is incomplete
  3. Log and skip invalid rows at the data source instead of emitting nil configs

Example fix

// before
func getConfigs() ([]*asynq.PeriodicTaskConfig, error) {
    return []*asynq.PeriodicTaskConfig{cfgFromDB(row1), cfgFromDB(row2)}, nil // may contain nil
}
// after
func getConfigs() ([]*asynq.PeriodicTaskConfig, error) {
    var out []*asynq.PeriodicTaskConfig
    for _, row := range rows {
        if c := cfgFromDB(row); c != nil { out = append(out, c) }
    }
    return out, nil
}
Defensive patterns

Strategy: validation

Validate before calling

cfgs, err := provider()
if err != nil { return err }
for i, c := range cfgs {
    if c == nil { return fmt.Errorf("config at index %d is nil", i) }
}

Type guard

func validConfig(c *asynq.PeriodicTaskConfig) bool { return c != nil }

Try / catch

if err := mgr.Run(); err != nil {
    if strings.Contains(err.Error(), "PeriodicTaskConfig cannot be nil") {
        // inspect provider output for nil entries
    }
    return err
}

Prevention

When it happens

Trigger: A PeriodicTaskConfigProvider callback returns a slice containing a nil *PeriodicTaskConfig element, causing sync to fail with this error at every sync interval.

Common situations: Building the config list from a database/flag source where some rows are empty; appending to a slice with a conditional that appends nil; JSON/YAML unmarshalling producing nil entries.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of hibiken/asynq@d135f1439b (2026-09-07). Data as JSON: /api/errors/7d48befc5f549cd0. Report an issue: GitHub.

Appendix: source

Thrown at periodic_task_manager.go:105

	Opts     []Option // optional: can be nil
}

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")
	}

View on GitHub (pinned to d135f1439b)