abpframework/abp · error · AbpException
Cannot convert period: {period} to cron expression.
Error message
Cannot convert period: {period} to cron expression. What it means
Thrown by HangfireDynamicBackgroundWorkerManager.GetCron when converting a dynamic worker's Period (milliseconds) to a cron expression and the period exceeds 31 days. Same conversion limitation as the static Hangfire manager: standard cron fields cannot express intervals longer than a month. This applies to dynamically registered workers scheduled by Period rather than cron.
Source
Thrown at framework/src/Volo.Abp.BackgroundWorkers.Hangfire/Volo/Abp/BackgroundWorkers/Hangfire/HangfireDynamicBackgroundWorkerManager.cs:182
}
else if (time.TotalMinutes <= 59)
{
var minutes = Math.Max(1, (int)Math.Round(time.TotalMinutes));
cron = $"*/{minutes} * * * *";
}
else if (time.TotalHours <= 23)
{
var hours = Math.Max(1, (int)Math.Round(time.TotalHours));
cron = $"0 */{hours} * * *";
}
else if (time.TotalDays <= 31)
{
var days = Math.Max(1, (int)Math.Round(time.TotalDays));
cron = $"0 0 0 1/{days} * *";
}
else
{
throw new AbpException($"Cannot convert period: {period} to cron expression.");
}
return cron;
}
}
View on GitHub (pinned to 7ed43b1931)
Solutions
- Reduce the Period to 31 days or fewer.
- Provide a CronExpression in the DynamicBackgroundWorkerSchedule instead of a Period (e.g. "0 0 1 * *" for monthly), since Hangfire's dynamic manager supports cron expressions.
- If the value is a unit error, correct the Period to the intended milliseconds.
Example fix
// before — dynamic worker with a 60-day period
await dynamicManager.AddAsync("quarterly-cleanup",
new DynamicBackgroundWorkerSchedule { Period = (int)TimeSpan.FromDays(60).TotalMilliseconds },
handler);
// after — use a cron expression instead
await dynamicManager.AddAsync("quarterly-cleanup",
new DynamicBackgroundWorkerSchedule { CronExpression = "0 0 1 1,4,7,10 *" },
handler); Defensive patterns
Strategy: validation
Validate before calling
var schedule = new DynamicBackgroundWorkerSchedule { Period = computedPeriod };
if (schedule.Period.HasValue && TimeSpan.FromMilliseconds(schedule.Period.Value).TotalDays > 31)
{
throw new InvalidOperationException("Period exceeds 31 days; set CronExpression instead for long intervals.");
}
schedule.Validate(); Type guard
static bool IsCronConvertiblePeriod(int periodMs) => TimeSpan.FromMilliseconds(periodMs).TotalDays <= 31;
Prevention
- For dynamic workers with intervals over 31 days, supply CronExpression instead of Period.
- Wrap dynamic schedule creation in a helper that enforces the period ceiling.
- Document which providers support cron and use them when long intervals are needed.
When it happens
Trigger: Calling AddAsync on the Hangfire dynamic background worker manager with a DynamicBackgroundWorkerSchedule whose Period (in ms) corresponds to more than 31 days. The GetCron converter is invoked because no CronExpression was supplied.
Common situations: Dynamically registering a long-running cleanup or archival worker with a multi-month Period. Passing a Period value that was meant in seconds but supplied in milliseconds, blowing past the 31-day ceiling.
Related errors
- Cannot convert period: {period} to cron expression, use Hang
- Cannot convert period: {period} to cron expression.
- The default in-memory background worker manager does not sup
- Period must be greater than 0 when provided. Given value: {P
- At least one of 'Period' or 'CronExpression' must be set.
AI-assisted analysis of abpframework/abp@7ed43b1931 (2026-08-13).
Data as JSON: /api/errors/63e6fa75475a729d.
Report an issue: GitHub.