{"record":{"id":"90aafee46a556852","repo":"hibiken/asynq","slug":"asynq-cannot-start-uninitialized-periodictaskmana","errorCode":null,"errorMessage":"asynq: cannot start uninitialized PeriodicTaskManager; use NewPeriodicTaskManager to initialize","messagePattern":"asynq: cannot start uninitialized PeriodicTaskManager; use NewPeriodicTaskManager to initialize","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"periodic_task_manager.go","lineNumber":122,"sourceCode":"\tif c == nil {\n\t\treturn fmt.Errorf(\"PeriodicTaskConfig cannot be nil\")\n\t}\n\tif c.Task == nil {\n\t\treturn fmt.Errorf(\"PeriodicTaskConfig.Task cannot be nil\")\n\t}\n\tif c.Cronspec == \"\" {\n\t\treturn fmt.Errorf(\"PeriodicTaskConfig.Cronspec cannot be empty\")\n\t}\n\treturn nil\n}\n\n// Start starts a scheduler and background goroutine to sync the scheduler with the configs\n// returned by the provider.\n//\n// Start returns any error encountered at start up time.\nfunc (mgr *PeriodicTaskManager) Start() error {\n\tif mgr.s == nil || mgr.p == nil {\n\t\tpanic(\"asynq: cannot start uninitialized PeriodicTaskManager; use NewPeriodicTaskManager to initialize\")\n\t}\n\tif err := mgr.initialSync(); err != nil {\n\t\treturn fmt.Errorf(\"asynq: %w\", err)\n\t}\n\tif err := mgr.s.Start(); err != nil {\n\t\treturn fmt.Errorf(\"asynq: %w\", err)\n\t}\n\tmgr.wg.Add(1)\n\tgo func() {\n\t\tdefer mgr.wg.Done()\n\t\tticker := time.NewTicker(mgr.syncInterval)\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-mgr.done:\n\t\t\t\tmgr.s.logger.Debugf(\"Stopping syncer goroutine\")\n\t\t\t\tticker.Stop()\n\t\t\t\treturn\n\t\t\tcase <-ticker.C:","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/hibiken/asynq/blob/d135f1439bee74e989b7f9b41ecd542cc87f024a/periodic_task_manager.go#L104-L140","documentation":"PeriodicTaskManager.Start panics when the manager's internal scheduler (mgr.s) or provider (mgr.p) is nil, i.e. the struct was created with plain &PeriodicTaskManager{} or via a zero-value composite literal instead of the required NewPeriodicTaskManager constructor. The library requires construction via NewPeriodicTaskManager, which wires the scheduler and provider, so Start on an uninitialized instance is a programming error.","triggerScenarios":"Calling Start on a PeriodicTaskManager built as &asynq.PeriodicTaskManager{} or asynq.PeriodicTaskManager{}; declaring the manager as a struct field and using it before assigning the result of NewPeriodicTaskManager; copying the manager value so internal fields end up nil.","commonSituations":"DI/manual wiring skipping the constructor; refactoring where NewPeriodicTaskManager's error return was dropped and the nil manager was kept; embedding the manager by value in another struct causing a partial copy.","solutions":["Construct with asynq.NewPeriodicTaskManager(asynq.PeriodicTaskManagerOpts{RedisConnOpt: ..., Provider: ...}) and use the returned pointer","Use mgr.Run() instead of calling Start manually if you want start+stop handled together","Check that the constructor's error return is handled and the non-nil result is stored","Never copy the PeriodicTaskManager value; always pass and store the *PeriodicTaskManager pointer"],"exampleFix":"// before\nvar mgr asynq.PeriodicTaskManager\nmgr.Start()\n\n// after\nmgr, err := asynq.NewPeriodicTaskManager(asynq.PeriodicTaskManagerOpts{\n    RedisConnOpt: asynq.RedisClientOpt{Addr: \":6379\"},\n    Provider:     myConfigProvider,\n})\nif err != nil { log.Fatal(err) }\nif err := mgr.Run(); err != nil { log.Fatal(err) }","handlingStrategy":"validation","validationCode":"if mgr == nil {\n    return errors.New(\"PeriodicTaskManager not constructed; use NewPeriodicTaskManager\")\n}\nif err := mgr.Run(); err != nil { log.Fatal(err) }","typeGuard":"func managerReady(mgr *asynq.PeriodicTaskManager) bool {\n    return mgr != nil\n}","tryCatchPattern":null,"preventionTips":["Always construct with NewPeriodicTaskManager; never use a zero-value PeriodicTaskManager","Store the returned *PeriodicTaskManager pointer; do not copy the struct by value","Handle the constructor's error and only Start/Run a non-nil manager","Prefer mgr.Run() over manual Start/Stop pairing"],"tags":["panic","initialization","go"],"backgroundTag":"invalid-state-transition","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"}