{"record":{"id":"73dda68f343987f2","repo":"hibiken/asynq","slug":"redisconnopt-redisuniversalclient-cannot-be-nil","errorCode":null,"errorMessage":"RedisConnOpt/RedisUniversalClient cannot be nil","messagePattern":"RedisConnOpt/RedisUniversalClient cannot be nil","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"periodic_task_manager.go","lineNumber":54,"sourceCode":"\tRedisUniversalClient redis.UniversalClient\n\n\t// Optional: scheduler options\n\t*SchedulerOpts\n\n\t// Optional: default is 3m\n\tSyncInterval time.Duration\n}\n\nconst defaultSyncInterval = 3 * time.Minute\n\n// NewPeriodicTaskManager returns a new PeriodicTaskManager instance.\n// The given opts should specify the RedisConnOp and PeriodicTaskConfigProvider at minimum.\nfunc NewPeriodicTaskManager(opts PeriodicTaskManagerOpts) (*PeriodicTaskManager, error) {\n\tif opts.PeriodicTaskConfigProvider == nil {\n\t\treturn nil, fmt.Errorf(\"PeriodicTaskConfigProvider cannot be nil\")\n\t}\n\tif opts.RedisConnOpt == nil && opts.RedisUniversalClient == nil {\n\t\treturn nil, fmt.Errorf(\"RedisConnOpt/RedisUniversalClient cannot be nil\")\n\t}\n\tvar scheduler *Scheduler\n\tif opts.RedisUniversalClient != nil {\n\t\tscheduler = NewSchedulerFromRedisClient(opts.RedisUniversalClient, opts.SchedulerOpts)\n\t} else {\n\t\tscheduler = NewScheduler(opts.RedisConnOpt, opts.SchedulerOpts)\n\t}\n\n\tsyncInterval := opts.SyncInterval\n\tif syncInterval == 0 {\n\t\tsyncInterval = defaultSyncInterval\n\t}\n\treturn &PeriodicTaskManager{\n\t\ts:            scheduler,\n\t\tp:            opts.PeriodicTaskConfigProvider,\n\t\tsyncInterval: syncInterval,\n\t\tdone:         make(chan struct{}),\n\t\tm:            make(map[string]string),","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/hibiken/asynq/blob/d135f1439bee74e989b7f9b41ecd542cc87f024a/periodic_task_manager.go#L36-L72","documentation":"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.","triggerScenarios":"Calling NewPeriodicTaskManager with a PeriodicTaskConfigProvider but leaving both RedisConnOpt and RedisUniversalClient nil; passing a zero-value RedisConnOpt struct pointer that is nil.","commonSituations":"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.","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"],"exampleFix":"// before\nmgr, err := asynq.NewPeriodicTaskManager(asynq.PeriodicTaskManagerOpts{\n    PeriodicTaskConfigProvider: getPeriodicConfigs,\n})\n// after\nmgr, err := asynq.NewPeriodicTaskManager(asynq.PeriodicTaskManagerOpts{\n    RedisConnOpt: asynq.RedisClientOpt{Addr: redisAddr},\n    PeriodicTaskConfigProvider: getPeriodicConfigs,\n})","handlingStrategy":"validation","validationCode":"if opts.RedisConnOpt == nil && opts.RedisUniversalClient == nil {\n    return errors.New(\"a Redis connection option must be set\")\n}\nmgr, err := asynq.NewPeriodicTaskManager(opts)","typeGuard":null,"tryCatchPattern":"mgr, err := asynq.NewPeriodicTaskManager(opts)\nif err != nil {\n    log.Fatalf(\"invalid periodic task manager opts: %v\", err)\n}","preventionTips":["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"],"tags":["configuration","redis","nil-check"],"backgroundTag":"missing-required-option","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"}