hibiken/asynq · error

RedisConnOpt/RedisUniversalClient cannot be nil

Error message

RedisConnOpt/RedisUniversalClient cannot be nil

What it means

NewPeriodicTaskManager returns this error when neither RedisConnOpt nor RedisUniversalClient is provided. The manager needs a Redis connection to run its scheduler, so at least one of the two mutually exclusive connection options must be set. Fails immediately at construction.

Solutions

  1. Set RedisConnOpt (e.g. asynq.RedisClientOpt{Addr: "localhost:6379"})
  2. Or set RedisUniversalClient with a ready go-redis universal client
  3. Verify the config source actually populated the Redis address before building opts

Example fix

// before
mgr, err := asynq.NewPeriodicTaskManager(asynq.PeriodicTaskManagerOpts{
    PeriodicTaskConfigProvider: getPeriodicConfigs,
})
// after
mgr, err := asynq.NewPeriodicTaskManager(asynq.PeriodicTaskManagerOpts{
    RedisConnOpt: asynq.RedisClientOpt{Addr: redisAddr},
    PeriodicTaskConfigProvider: getPeriodicConfigs,
})
Defensive patterns

Strategy: validation

Validate before calling

if opts.RedisConnOpt == nil && opts.RedisUniversalClient == nil {
    return errors.New("a Redis connection option must be set")
}
mgr, err := asynq.NewPeriodicTaskManager(opts)

Try / catch

mgr, err := asynq.NewPeriodicTaskManager(opts)
if err != nil {
    log.Fatalf("invalid periodic task manager opts: %v", err)
}

Prevention

When it happens

Trigger: Calling NewPeriodicTaskManager with a PeriodicTaskConfigProvider but leaving both RedisConnOpt and RedisUniversalClient nil; passing a zero-value RedisConnOpt struct pointer that is nil.

Common situations: Config assembled from env vars where the Redis address variable is empty and the option becomes nil; migrating from RedisClientOpt to RedisUniversalClient and removing both; test fixtures with partial opts.

Understand the failure class

Background: "Must pass :limit option" / "Missing required option" — required option errors explained — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at periodic_task_manager.go:54

	RedisUniversalClient redis.UniversalClient

	// Optional: scheduler options
	*SchedulerOpts

	// Optional: default is 3m
	SyncInterval time.Duration
}

const defaultSyncInterval = 3 * time.Minute

// NewPeriodicTaskManager returns a new PeriodicTaskManager instance.
// The given opts should specify the RedisConnOp and PeriodicTaskConfigProvider at minimum.
func NewPeriodicTaskManager(opts PeriodicTaskManagerOpts) (*PeriodicTaskManager, error) {
	if opts.PeriodicTaskConfigProvider == nil {
		return nil, fmt.Errorf("PeriodicTaskConfigProvider cannot be nil")
	}
	if opts.RedisConnOpt == nil && opts.RedisUniversalClient == nil {
		return nil, fmt.Errorf("RedisConnOpt/RedisUniversalClient cannot be nil")
	}
	var scheduler *Scheduler
	if opts.RedisUniversalClient != nil {
		scheduler = NewSchedulerFromRedisClient(opts.RedisUniversalClient, opts.SchedulerOpts)
	} else {
		scheduler = NewScheduler(opts.RedisConnOpt, opts.SchedulerOpts)
	}

	syncInterval := opts.SyncInterval
	if syncInterval == 0 {
		syncInterval = defaultSyncInterval
	}
	return &PeriodicTaskManager{
		s:            scheduler,
		p:            opts.PeriodicTaskConfigProvider,
		syncInterval: syncInterval,
		done:         make(chan struct{}),
		m:            make(map[string]string),

View on GitHub (pinned to d135f1439b)