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

  1. Reduce the Period to 31 days or fewer.
  2. 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.
  3. 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

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


AI-assisted analysis of abpframework/abp@7ed43b1931 (2026-08-13). Data as JSON: /api/errors/63e6fa75475a729d. Report an issue: GitHub.