abpframework/abp · error · AbpException
The default in-memory background worker manager does not sup
Error message
The default in-memory background worker manager does not support CronExpression for dynamic worker '{workerName}'. Please clear CronExpression and use Period-based scheduling, or use a scheduler-backed provider (Hangfire or Quartz). What it means
Thrown by DefaultDynamicBackgroundWorkerManager.AddAsync when the supplied DynamicBackgroundWorkerSchedule has a non-empty CronExpression. The default in-memory dynamic worker manager only supports Period-based scheduling (it uses an AbpAsyncTimer); it has no cron engine. The error tells you to drop CronExpression and use Period, or switch to Hangfire/Quartz which support cron.
Source
Thrown at framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/DefaultDynamicBackgroundWorkerManager.cs:47
_dynamicWorkers = new ConcurrentDictionary<string, InMemoryDynamicBackgroundWorker>();
_semaphore = new SemaphoreSlim(1, 1);
}
public virtual async Task AddAsync(
string workerName,
DynamicBackgroundWorkerSchedule schedule,
DynamicBackgroundWorkerHandler handler,
CancellationToken cancellationToken = default)
{
Check.NotNullOrWhiteSpace(workerName, nameof(workerName));
Check.NotNull(schedule, nameof(schedule));
Check.NotNull(handler, nameof(handler));
schedule.Validate();
if (!schedule.CronExpression.IsNullOrWhiteSpace())
{
throw new AbpException(
$"The default in-memory background worker manager does not support CronExpression for dynamic worker '{workerName}'. " +
"Please clear CronExpression and use Period-based scheduling, or use a scheduler-backed provider (Hangfire or Quartz).");
}
await _semaphore.WaitAsync(cancellationToken);
try
{
if (_isDisposed)
{
throw new ObjectDisposedException(nameof(DefaultDynamicBackgroundWorkerManager));
}
if (_dynamicWorkers.TryRemove(workerName, out var existingWorker))
{
await existingWorker.StopAsync(cancellationToken);
Logger.LogInformation("Replaced existing dynamic worker: {WorkerName}", workerName);
}
View on GitHub (pinned to 7ed43b1931)
Solutions
- Clear CronExpression and set a Period (in ms) on the schedule: new DynamicBackgroundWorkerSchedule { Period = 60000 }.
- Add the Hangfire or Quartz background workers module to the project so the cron-capable dynamic manager resolves instead of the default.
- If you need both cron and the in-memory manager, reconsider — use a provider that supports cron.
Example fix
// before — cron expression with default in-memory manager (throws)
await dynamicManager.AddAsync("cron-worker",
new DynamicBackgroundWorkerSchedule { CronExpression = "0 */5 * * *" },
handler);
// after — use Period instead
await dynamicManager.AddAsync("periodic-worker",
new DynamicBackgroundWorkerSchedule { Period = 300000 }, // 5 minutes
handler); Defensive patterns
Strategy: validation
Validate before calling
var schedule = new DynamicBackgroundWorkerSchedule { Period = 60000 };
if (!schedule.CronExpression.IsNullOrWhiteSpace() && dynamicManager is DefaultDynamicBackgroundWorkerManager)
{
throw new NotSupportedException("Default in-memory manager does not support cron; clear CronExpression or use Hangfire/Quartz.");
} Type guard
static bool ManagerSupportsCron(IDynamicBackgroundWorkerManager mgr) => mgr is not DefaultDynamicBackgroundWorkerManager;
Try / catch
try { await dynamicManager.AddAsync(name, schedule, handler, ct); }
catch (AbpException ex) when (ex.Message.Contains("does not support CronExpression"))
{
logger.LogError(ex, "Clear CronExpression and use Period, or switch to Hangfire/Quartz.");
} Prevention
- Default to Period-based schedules when using the in-memory manager.
- Detect the active provider at startup and reject cron-based schedules early.
- Add the Hangfire or Quartz module if cron scheduling is required.
When it happens
Trigger: Calling AddAsync on IDynamicBackgroundWorkerManager (resolved as DefaultDynamicBackgroundWorkerManager, the built-in implementation) with a DynamicBackgroundWorkerSchedule where CronExpression is set (e.g. "0 * * * *"). This happens when no Hangfire or Quartz background workers module is loaded, so the default in-memory manager is active.
Common situations: Developing with cron-based scheduling locally where the default manager is used (no Hangfire/Quartz dependency), then deploying the same schedule to production. Copying a schedule object that was built for Hangfire into a project without the Hangfire provider.
Related errors
- Cannot convert period: {period} to cron expression.
- Cannot convert period: {period} to cron expression, use Hang
- Cannot convert period: {period} to cron expression.
- TickerQ does not support dynamic background worker registrat
- TickerQ does not support dynamic background worker registrat
AI-assisted analysis of abpframework/abp@7ed43b1931 (2026-08-13).
Data as JSON: /api/errors/01bb308628b4f753.
Report an issue: GitHub.