{"record":{"id":"17c4a70171c4ba4c","repo":"hibiken/asynq","slug":"asynq-w-17c4a7","errorCode":null,"errorMessage":"asynq: %w","messagePattern":"asynq: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"periodic_task_manager.go","lineNumber":125,"sourceCode":"\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:\n\t\t\t\tmgr.sync()\n\t\t\t}\n\t\t}","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/hibiken/asynq/blob/d135f1439bee74e989b7f9b41ecd542cc87f024a/periodic_task_manager.go#L107-L143","documentation":"PeriodicTaskManager.Start wraps any error from the initial configuration sync with the \"asynq: \" prefix. The underlying cause is almost always the config provider failing (GetConfigs error) or a config failing validation. It is a wrapper, so inspect the wrapped error for the real cause.","triggerScenarios":"Calling mgr.Start() (directly or via Run) when mgr.p.GetConfigs() returns an error, or when initialSync validation fails (nil config, nil Task, empty Cronspec, duplicate IDs).","commonSituations":"Redis-backed or file-based provider unreachable at startup; provider returns configs with empty cronspecs; app redeploy where the config service is not yet up.","solutions":["Read the wrapped error (%w chain) to find the root cause","Verify the ConfigProvider is initialized and its backing store is reachable before Start","Validate provider output (non-nil, valid cronspecs) before returning it from GetConfigs"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if err := mgr.p.GetConfigs(); err != nil {\n    return fmt.Errorf(\"provider not ready: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := mgr.Start(); err != nil {\n    var root error\n    for e := err; e != nil; e = errors.Unwrap(e) { root = e }\n    log.Fatalf(\"periodic task manager failed to start: %v (root: %v)\", err, root)\n}","preventionTips":["Unwrap the error chain with errors.Unwrap to find the true cause","Pre-flight the provider's backing store before Start","Log provider errors inside your GetConfigs implementation for faster diagnosis"],"tags":["asynq","scheduler","startup"],"backgroundTag":"invalid-config-value","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"}