{"record":{"id":"8974f4cf80d7ee08","repo":"HangfireIO/Hangfire","slug":"factory","errorCode":null,"errorMessage":"factory","messagePattern":"factory","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"src/Hangfire.Core/BackgroundJobServer.cs","lineNumber":207,"sourceCode":"            [CanBeNull] IBackgroundJobFactory factory,\n            [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)","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/HangfireIO/Hangfire/blob/c236dd0f930f831ec151e436e138ddc429a02a72/src/Hangfire.Core/BackgroundJobServer.cs#L189-L225","documentation":"This ArgumentNullException(\"factory\") is thrown inside GetRequiredProcesses (called from the advanced BackgroundJobServer constructor) when factory is null but at least one of performer or stateChanger is non-null. The code treats factory/performer/stateChanger as all-or-nothing: if all three are null it auto-creates them from filterProvider/activator; otherwise it requires all three to be provided. Passing a custom performer or stateChanger without also supplying a factory triggers this throw.","triggerScenarios":"Calling the advanced constructor with a non-null performer or stateChanger but a null factory, e.g. new BackgroundJobServer(opts, storage, extra, null, null, null, customPerformer, null) — factory is null while performer is set, so the else-branch throws on factory.","commonSituations":"Customizing job execution by supplying only the performer (or only the state changer) thinking the others default; partial migration to custom services; misunderstanding the all-or-nothing contract documented in the [Obsolete] advanced constructor.","solutions":["Provide all three of factory, performer and stateChanger when you customize any one of them.","Or pass all three as null so Hangfire auto-creates them from the filter provider / activator.","Construct the missing pieces yourself, e.g. factory = new BackgroundJobFactory(filterProvider ?? JobFilterProviders.Providers).","Migrate off the [Obsolete] advanced constructor by building your own BackgroundJobServer-like type as the obsolete message advises."],"exampleFix":"// before\nnew BackgroundJobServer(opts, storage, extra, null, null, null, customPerformer, null);\n\n// after\nvar filters = JobFilterProviders.Providers;\nnew BackgroundJobServer(opts, storage, extra,\n    filters, JobActivator.Current,\n    new BackgroundJobFactory(filters),\n    customPerformer,\n    new BackgroundJobStateChanger(filters));","handlingStrategy":"validation","validationCode":"if (factory is null && (performer 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 == \"factory\") { throw new InvalidOperationException(\"Custom services must be supplied together.\", ex); }","preventionTips":["Treat factory/performer/stateChanger as all-or-nothing.","Pass all three as null to use defaults.","Migrate off the [Obsolete] advanced 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"}