{"record":{"id":"4c59941943321b8d","repo":"HangfireIO/Hangfire","slug":"performer","errorCode":null,"errorMessage":"performer","messagePattern":"performer","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"src/Hangfire.Core/BackgroundJobServer.cs","lineNumber":208,"sourceCode":"            [CanBeNull] IBackgroundJobPerformer performer,\n            [CanBeNull] IBackgroundJobStateChanger stateChanger)\n        {\n            var processes = new List<IBackgroundProcessDispatcherBuilder>();\n            var timeZoneResolver = _options.TimeZoneResolver ?? new DefaultTimeZoneResolver();\n\n            if (factory == null && performer == null && stateChanger == null)\n            {\n                filterProvider = filterProvider ?? _options.FilterProvider ?? JobFilterProviders.Providers;\n                activator = activator ?? _options.Activator ?? JobActivator.Current;\n\n                factory = new BackgroundJobFactory(filterProvider);\n                performer = new BackgroundJobPerformer(filterProvider, activator, _options.TaskScheduler);\n                stateChanger = new BackgroundJobStateChanger(filterProvider);\n            }\n            else\n            {\n                if (factory == null) throw new ArgumentNullException(nameof(factory));\n                if (performer == null) throw new ArgumentNullException(nameof(performer));\n                if (stateChanger == null) throw new ArgumentNullException(nameof(stateChanger));\n            }\n\n            processes.Add(new Worker(_options.Queues, performer, stateChanger).UseBackgroundPool(_options.WorkerCount, _options.WorkerThreadConfigurationAction));\n\n            if (!_options.IsLightweightServer)\n            {\n                processes.Add(\n                    new DelayedJobScheduler(_options.SchedulePollingInterval, stateChanger)\n                    {\n                        TaskScheduler = _options.TaskScheduler,\n                        MaxDegreeOfParallelism = _options.MaxDegreeOfParallelismForSchedulers\n                    }\n                    .UseBackgroundPool(1));\n\n                processes.Add(\n                    new RecurringJobScheduler(factory, _options.SchedulePollingInterval, timeZoneResolver)\n                        {","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/HangfireIO/Hangfire/blob/c236dd0f930f831ec151e436e138ddc429a02a72/src/Hangfire.Core/BackgroundJobServer.cs#L190-L226","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nnew BackgroundJobServer(opts, storage, extra, null, null, customFactory, null, null);\n\n// after\nvar filters = JobFilterProviders.Providers;\nnew BackgroundJobServer(opts, storage, extra,\n    filters, JobActivator.Current,\n    customFactory,\n    new BackgroundJobPerformer(filters, JobActivator.Current, opts.TaskScheduler),\n    new BackgroundJobStateChanger(filters));","handlingStrategy":"validation","validationCode":"if (performer is null && (factory is not null || stateChanger is not null))\n    throw new InvalidOperationException(\"Supply all three of factory, performer and stateChanger, or none.\");\nnew BackgroundJobServer(opts, storage, extra, filters, activator, factory, performer, stateChanger);","typeGuard":"static bool AreServicesConsistent(IBackgroundJobFactory f, IBackgroundJobPerformer p, IBackgroundJobStateChanger s)\n    => (f is null && p is null && s is null) || (f is not null && p is not null && s is not null);","tryCatchPattern":"try { new BackgroundJobServer(opts, storage, extra, filters, activator, factory, performer, stateChanger); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"performer\") { throw new InvalidOperationException(\"Custom services must be supplied together.\", ex); }","preventionTips":["Treat the three services as all-or-nothing.","Construct missing services explicitly when customizing.","Move off the [Obsolete] constructor."],"tags":["csharp","hangfire","argumentnullexception","constructor","custom-services","background-jobs"],"backgroundTag":null,"analyzedSha":"c236dd0f930f831ec151e436e138ddc429a02a72","analyzedAt":"2026-08-13T20:27:11.027Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}