HangfireIO/Hangfire · error · ArgumentNullException
performer
Error message
performer
What it means
This ArgumentNullException("performer") is thrown inside GetRequiredProcesses (called from the advanced BackgroundJobServer constructor) when performer is null but at least one of factory or stateChanger is non-null. Same all-or-nothing contract as factory/stateChanger: when any of the three is supplied, all three must be supplied. The Worker process built afterwards needs a performer, so a null performer cannot be tolerated here.
Source
Thrown at src/Hangfire.Core/BackgroundJobServer.cs:208
[CanBeNull] IBackgroundJobPerformer performer,
[CanBeNull] IBackgroundJobStateChanger stateChanger)
{
var processes = new List<IBackgroundProcessDispatcherBuilder>();
var timeZoneResolver = _options.TimeZoneResolver ?? new DefaultTimeZoneResolver();
if (factory == null && performer == null && stateChanger == null)
{
filterProvider = filterProvider ?? _options.FilterProvider ?? JobFilterProviders.Providers;
activator = activator ?? _options.Activator ?? JobActivator.Current;
factory = new BackgroundJobFactory(filterProvider);
performer = new BackgroundJobPerformer(filterProvider, activator, _options.TaskScheduler);
stateChanger = new BackgroundJobStateChanger(filterProvider);
}
else
{
if (factory == null) throw new ArgumentNullException(nameof(factory));
if (performer == null) throw new ArgumentNullException(nameof(performer));
if (stateChanger == null) throw new ArgumentNullException(nameof(stateChanger));
}
processes.Add(new Worker(_options.Queues, performer, stateChanger).UseBackgroundPool(_options.WorkerCount, _options.WorkerThreadConfigurationAction));
if (!_options.IsLightweightServer)
{
processes.Add(
new DelayedJobScheduler(_options.SchedulePollingInterval, stateChanger)
{
TaskScheduler = _options.TaskScheduler,
MaxDegreeOfParallelism = _options.MaxDegreeOfParallelismForSchedulers
}
.UseBackgroundPool(1));
processes.Add(
new RecurringJobScheduler(factory, _options.SchedulePollingInterval, timeZoneResolver)
{View on GitHub (pinned to c236dd0f93)
Solutions
- Provide all three of factory, performer and stateChanger when customizing any one.
- Or pass all three as null to let Hangfire build them.
- Construct the missing performer yourself, e.g. performer = new BackgroundJobPerformer(filters, activator, opts.TaskScheduler).
- Move off the [Obsolete] constructor per its deprecation message.
Example fix
// before
new BackgroundJobServer(opts, storage, extra, null, null, customFactory, null, null);
// after
var filters = JobFilterProviders.Providers;
new BackgroundJobServer(opts, storage, extra,
filters, JobActivator.Current,
customFactory,
new BackgroundJobPerformer(filters, JobActivator.Current, opts.TaskScheduler),
new BackgroundJobStateChanger(filters)); Defensive patterns
Strategy: validation
Validate before calling
if (performer is null && (factory is not null || stateChanger is not null))
throw new InvalidOperationException("Supply all three of factory, performer and stateChanger, or none.");
new BackgroundJobServer(opts, storage, extra, filters, activator, factory, performer, stateChanger); Type guard
static bool AreServicesConsistent(IBackgroundJobFactory f, IBackgroundJobPerformer p, IBackgroundJobStateChanger s)
=> (f is null && p is null && s is null) || (f is not null && p is not null && s is not null); Try / catch
try { new BackgroundJobServer(opts, storage, extra, filters, activator, factory, performer, stateChanger); }
catch (ArgumentNullException ex) when (ex.ParamName == "performer") { throw new InvalidOperationException("Custom services must be supplied together.", ex); } Prevention
- Treat the three services as all-or-nothing.
- Construct missing services explicitly when customizing.
- Move off the [Obsolete] constructor.
When it happens
Trigger: Calling the advanced constructor with a non-null factory or stateChanger but a null performer, e.g. new BackgroundJobServer(opts, storage, extra, null, null, customFactory, null, null) — performer is null while factory is set, so the else-branch throws on performer.
Common situations: Supplying a custom factory (e.g. to add filters) without also supplying a performer; partial customization; misunderstanding the all-or-nothing rule for the three services.
Related errors
AI-assisted analysis of HangfireIO/Hangfire@c236dd0f93 (2026-08-13).
Data as JSON: /api/errors/4c59941943321b8d.
Report an issue: GitHub.