{"record":{"id":"dd7d6ed55f0fcaf4","repo":"hibiken/asynq","slug":"periodictaskconfigprovider-cannot-be-nil","errorCode":null,"errorMessage":"PeriodicTaskConfigProvider cannot be nil","messagePattern":"PeriodicTaskConfigProvider cannot be nil","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"periodic_task_manager.go","lineNumber":51,"sourceCode":"\tRedisConnOpt RedisConnOpt\n\n\t// Optional: if RedisUniversalClient is non nil, RedisConnOpt is ignored.\n\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,","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/hibiken/asynq/blob/d135f1439bee74e989b7f9b41ecd542cc87f024a/periodic_task_manager.go#L33-L69","documentation":"NewPeriodicTaskManager validates its options before constructing the manager and returns this error when PeriodicTaskConfigProvider is nil. The provider is the callback that supplies the list of periodic task configs during sync, so the manager cannot function without it. This fails fast at construction time.","triggerScenarios":"Calling NewPeriodicTaskManager(PeriodicTaskManagerOpts{}) or omitting the PeriodicTaskConfigProvider field while setting RedisConnOpt/SchedulerOpts.","commonSituations":"Copy-pasting an example and dropping the provider field; building opts dynamically where the provider assignment is skipped; refactoring that renamed the field.","solutions":["Set PeriodicTaskConfigProvider to a function returning ([]*PeriodicTaskConfig, error)","Double-check the PeriodicTaskManagerOpts literal includes the provider","Add a unit test constructing the manager with production opts"],"exampleFix":"// before\nmgr, err := asynq.NewPeriodicTaskManager(asynq.PeriodicTaskManagerOpts{\n    RedisConnOpt: asynq.RedisClientOpt{Addr: redisAddr},\n})\n// after\nmgr, err := asynq.NewPeriodicTaskManager(asynq.PeriodicTaskManagerOpts{\n    RedisConnOpt: asynq.RedisClientOpt{Addr: redisAddr},\n    PeriodicTaskConfigProvider: getPeriodicConfigs,\n})","handlingStrategy":"validation","validationCode":"if opts.PeriodicTaskConfigProvider == nil {\n    return errors.New(\"PeriodicTaskConfigProvider 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":["Always set PeriodicTaskConfigProvider in PeriodicTaskManagerOpts","Build opts in one reviewed constructor function","Add a constructor smoke test to CI","Enable linters flagging zero-value struct literals"],"tags":["configuration","validation","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"}