{"record":{"id":"02c222d35aea1161","repo":"HangfireIO/Hangfire","slug":"threadfactory-02c222","errorCode":null,"errorMessage":"threadFactory","messagePattern":"threadFactory","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"src/Hangfire.Core/Processing/BackgroundTaskScheduler.cs","lineNumber":109,"sourceCode":"            : this(threadStart => DefaultThreadFactory(threadStart, threadCount), DefaultExceptionHandler)\n        {\n        }\n\n        /// <summary>Initializes a new instance of the <see cref=\"BackgroundTaskScheduler\"/>\n        /// class with the specified <paramref name=\"threadFactory\"/> and an optional exception\n        /// handler. All the created threads will be started to dispatch <see cref=\"Task\"/>\n        /// instances scheduled to run on this scheduler.</summary>\n        /// <param name=\"threadFactory\">Callback that creates one or more dedicated threads.</param>\n        /// <param name=\"exceptionHandler\">Optional callback that is invoked when unhandled exception occurs \n        /// in one of the threads. After this event this instance is considered stopped.</param>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"threadFactory\"/> is <see langword=\"null\"/>.</exception>\n        /// <exception cref=\"ArgumentException\"><paramref name=\"threadFactory\"/> returned <see langword=\"null\"/> or zero threads.</exception>\n        /// <exception cref=\"ArgumentException\"><paramref name=\"threadFactory\"/> returned at least one thread not in the <see cref=\"ThreadState.Unstarted\"/> state.</exception>\n        public BackgroundTaskScheduler(\n            [NotNull] Func<ThreadStart, IEnumerable<Thread>> threadFactory,\n            [CanBeNull] Action<Exception> exceptionHandler)\n        {\n            if (threadFactory == null) throw new ArgumentNullException(nameof(threadFactory));\n\n            _exceptionHandler = exceptionHandler;\n            _semaphore = new Semaphore(0, Int32.MaxValue);\n\n            // Stopped event should always be the first in this array, see the DispatchLoop method.\n            _waitHandles = new WaitHandle[] { _stopped, _semaphore };\n\n#if !NETSTANDARD1_3\n            AppDomainUnloadMonitor.EnsureInitialized();\n#endif\n\n            _threads = threadFactory(DispatchLoop)?.ToArray();\n\n            if (_threads == null || _threads.Length == 0)\n            {\n                throw new ArgumentException(\"At least one non-started thread should be created.\", nameof(threadFactory));\n            }\n","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/HangfireIO/Hangfire/blob/c236dd0f930f831ec151e436e138ddc429a02a72/src/Hangfire.Core/Processing/BackgroundTaskScheduler.cs#L91-L127","documentation":"Thrown by the public BackgroundTaskScheduler(Func<ThreadStart, IEnumerable<Thread>>, Action<Exception>) constructor when the threadFactory argument is null. The scheduler depends entirely on the factory to create its dedicated worker threads, so a null factory cannot proceed.","triggerScenarios":"Calling `new BackgroundTaskScheduler(null, handler)` or passing a null threadFactory. Also reachable if a caller resolves the factory lazily and it comes back null.","commonSituations":"Custom hosting code that builds a BackgroundTaskScheduler with a conditional factory that evaluated to null; a refactor that removed the factory expression; DI misregistration returning null for the factory delegate.","solutions":["Pass a non-null Func<ThreadStart, IEnumerable<Thread>>; use the parameterless ctor or the (int) ctor if you want the built-in factory.","Guard the call site: throw a descriptive exception if the factory is null before constructing.","Verify the source producing the factory is initialised."],"exampleFix":"// before\nvar scheduler = new BackgroundTaskScheduler(null, ex => Log(ex));\n\n// after\nvar scheduler = new BackgroundTaskScheduler(\n    start => Enumerable.Range(0, 4).Select(i => new Thread(start) { IsBackground = true, Name = $\"Worker #{i}\" }),\n    ex => Log(ex));","handlingStrategy":"validation","validationCode":"if (threadFactory == null) throw new ArgumentNullException(nameof(threadFactory));\nvar scheduler = new BackgroundTaskScheduler(threadFactory, handler);","typeGuard":null,"tryCatchPattern":"try { var s = new BackgroundTaskScheduler(factory, handler); }\ncatch (ArgumentNullException ex) when (ex.ParamName == nameof(threadFactory))\n{ factory = DefaultFactory; /* retry */ }","preventionTips":["Use the parameterless or (int) constructor unless you need a custom factory.","Resolve the factory before constructing the scheduler.","Never pass a conditional expression that can evaluate to null."],"tags":["hangfire","null-argument","argument-validation","task-scheduler","threading"],"backgroundTag":null,"analyzedSha":"c236dd0f930f831ec151e436e138ddc429a02a72","analyzedAt":"2026-08-13T20:27:11.027Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}