{"record":{"id":"3feec550fa8e058f","repo":"abpframework/abp","slug":"cannot-convert-period-period-to-cron-expression-3feec5","errorCode":null,"errorMessage":"Cannot convert period: {period} to cron expression.","messagePattern":"Cannot convert period: (.+?) to cron expression\\.","errorType":"exception","errorClass":"AbpException","httpStatus":null,"severity":"error","filePath":"framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQBackgroundWorkerManager.cs","lineNumber":103,"sourceCode":"            var minutes = (int)Math.Round(time.TotalMinutes);\n            return $\"*/{minutes} * * * *\";\n        }\n\n        if (time.TotalHours < 24)\n        {\n            // Run every N hours\n            var hours = (int)Math.Round(time.TotalHours);\n            return $\"0 */{hours} * * *\";\n        }\n\n        if (time.TotalDays <= 31)\n        {\n            // Run every N days\n            var days = (int)Math.Round(time.TotalDays);\n            return $\"0 0 */{days} * *\";\n        }\n\n        throw new AbpException($\"Cannot convert period: {period} to cron expression.\");\n    }\n}\n","sourceCodeStart":85,"sourceCodeEnd":106,"githubUrl":"https://github.com/abpframework/abp/blob/7ed43b1931b9df46a50c0c59148a18645641d0df/framework/src/Volo.Abp.BackgroundWorkers.TickerQ/Volo/Abp/BackgroundWorkers/TickerQ/AbpTickerQBackgroundWorkerManager.cs#L85-L106","documentation":"Thrown by AbpTickerQBackgroundWorkerManager.GetCron when converting a worker's Period (milliseconds) to a cron expression and the period exceeds 31 days. The TickerQ cron converter covers sub-minute up to monthly intervals; periods longer than 31 days have no cron representation in this logic.","triggerScenarios":"Registering a periodic worker under the TickerQ provider with Period set to more than 31 days (2,678,400,000 ms) and no CronExpression. The AddAsync flow calls GetCron(period) because cronExpression was null.","commonSituations":"A long-interval maintenance worker (quarterly/yearly) registered with a Period value. A unit confusion where a value meant as seconds was supplied as milliseconds, exceeding the ceiling.","solutions":["Reduce the Period to 31 days or fewer.","Set a CronExpression on the worker for intervals longer than a month (e.g. \"0 0 1 1 *\" for January 1st each year).","Correct any millisecond/second unit mismatch in the Period value."],"exampleFix":"// before\npublic class YearlyAuditWorker : AsyncPeriodicBackgroundWorkerBase\n{\n    public YearlyAuditWorker()\n    {\n        Period = (int)TimeSpan.FromDays(365).TotalMilliseconds; // throws\n    }\n}\n\n// after — use a cron expression\npublic class YearlyAuditWorker : AsyncPeriodicBackgroundWorkerBase\n{\n    public YearlyAuditWorker()\n    {\n        CronExpression = \"0 0 1 1 *\";\n    }\n}","handlingStrategy":"validation","validationCode":"if (worker.Period.HasValue && TimeSpan.FromMilliseconds(worker.Period.Value).TotalDays > 31)\n{\n    throw new InvalidOperationException(\"Period exceeds 31 days for TickerQ; set CronExpression instead.\");\n}","typeGuard":"static bool IsCronConvertiblePeriod(int periodMs) => TimeSpan.FromMilliseconds(periodMs).TotalDays <= 31;","tryCatchPattern":null,"preventionTips":["Keep TickerQ worker periods at or below 31 days.","For longer intervals, set CronExpression on the worker.","Validate periods centrally during module configuration."],"tags":["tickerq","background-workers","cron","scheduling","period-conversion"],"backgroundTag":null,"analyzedSha":"7ed43b1931b9df46a50c0c59148a18645641d0df","analyzedAt":"2026-08-13T16:26:11.351Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}