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
- Set RedisConnOpt (e.g. asynq.RedisClientOpt{Addr: "localhost:6379"})
- Or set RedisUniversalClient with a ready go-redis universal client
- 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
- Set exactly one of RedisConnOpt or RedisUniversalClient
- Validate the Redis address env var before constructing opts
- Fail fast at startup with a clear message
- Test config loading with integration tests
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
- asynq: could not parse redis uri
- asynq: unsupported uri scheme
- asynq: could not parse redis uri: database number should be…
- PeriodicTaskConfigProvider cannot be nil
- asynq: unsupported RedisConnOpt type %T
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)