HangfireIO/Hangfire · error · ArgumentNullException
taskScheduler
Error message
taskScheduler
What it means
Thrown by BackgroundDispatcherAsync's constructor (internal) when the TaskScheduler argument is null. The dispatcher schedules each dispatch loop task onto that scheduler (Task.Factory.StartNew(..., _taskScheduler)), so a null scheduler has nowhere to run.
Source
Thrown at src/Hangfire.Core/Processing/BackgroundDispatcherAsync.cs:52
private readonly object _state;
private readonly TaskScheduler _taskScheduler;
private readonly bool _ownsScheduler;
public BackgroundDispatcherAsync(
[NotNull] IBackgroundExecution execution,
[NotNull] Func<Guid, object, Task> action,
[CanBeNull] object state,
[NotNull] TaskScheduler taskScheduler,
int maxConcurrency,
bool ownsScheduler)
{
if (maxConcurrency <= 0) throw new ArgumentOutOfRangeException(nameof(maxConcurrency));
_execution = execution ?? throw new ArgumentNullException(nameof(execution));
_action = action ?? throw new ArgumentNullException(nameof(action));
_state = state;
_taskScheduler = taskScheduler ?? throw new ArgumentNullException(nameof(taskScheduler));
_ownsScheduler = ownsScheduler;
#if !NETSTANDARD1_3
AppDomainUnloadMonitor.EnsureInitialized();
#endif
_stopped = new CountdownEvent(maxConcurrency);
for (var i = 0; i < maxConcurrency; i++)
{
Task.Factory.StartNew(
DispatchLoop,
CancellationToken.None,
TaskCreationOptions.None,
_taskScheduler).Unwrap();
}
}
View on GitHub (pinned to c236dd0f93)
Solutions
- Pass a non-null TaskScheduler — typically a BackgroundTaskScheduler instance or TaskScheduler.Default.
- Resolve the scheduler before constructing the dispatcher and validate it is non-null.
- Fix the DI registration so the scheduler service is always provided.
Example fix
// before var dispatcher = new BackgroundDispatcherAsync(execution, action, state, null, 4, false); // after var scheduler = scheduler ?? new BackgroundTaskScheduler(); var dispatcher = new BackgroundDispatcherAsync(execution, action, state, scheduler, 4, ownsScheduler: true);
Defensive patterns
Strategy: validation
Validate before calling
TaskScheduler scheduler = resolvedScheduler ?? new BackgroundTaskScheduler();
Prevention
- Default to a BackgroundTaskScheduler or TaskScheduler.Default when none is supplied.
- Resolve the scheduler before building the dispatcher.
- Check DI registration for the scheduler service.
When it happens
Trigger: Constructing BackgroundDispatcherAsync with taskScheduler == null. Happens when the caller passes a null BackgroundTaskScheduler or TaskScheduler.Default resolution failed.
Common situations: A hosting extension resolves the scheduler lazily and the resolution returned null; a custom server builder omitted the scheduler argument; DI container misregistration for the scheduler service.
Related errors
AI-assisted analysis of HangfireIO/Hangfire@c236dd0f93 (2026-08-13).
Data as JSON: /api/errors/025fcdc96d23f02f.
Report an issue: GitHub.