HangfireIO/Hangfire · error · ArgumentNullException

threadFactory

Error message

threadFactory

What it means

Thrown as ArgumentNullException by the BackgroundDispatcher constructor when the 'threadFactory' Func<ThreadStart, IEnumerable<Thread>> argument is null. BackgroundDispatcher is an internal worker that spawns one or more threads to run the dispatch loop; the threadFactory is the only way to create those threads, so a null factory aborts construction at line 45.

Source

Thrown at src/Hangfire.Core/Processing/BackgroundDispatcher.cs:45

namespace Hangfire.Processing
{
    internal sealed class BackgroundDispatcher : IBackgroundDispatcher
    {
        private readonly ILog _logger = LogProvider.GetLogger(typeof(BackgroundDispatcher));
        private readonly CountdownEvent _stopped;

        private readonly IBackgroundExecution _execution;
        private readonly Action<Guid, object> _action;
        private readonly object _state;

        public BackgroundDispatcher(
            [NotNull] IBackgroundExecution execution,
            [NotNull] Action<Guid, object> action,
            [CanBeNull] object state,
            [NotNull] Func<ThreadStart, IEnumerable<Thread>> threadFactory)
        {
            if (threadFactory == null) throw new ArgumentNullException(nameof(threadFactory));

            _execution = execution ?? throw new ArgumentNullException(nameof(execution));
            _action = action ?? throw new ArgumentNullException(nameof(action));
            _state = state;

#if !NETSTANDARD1_3
            AppDomainUnloadMonitor.EnsureInitialized();
#endif

            var threads = threadFactory(DispatchLoop)?.ToArray();

            if (threads == null || threads.Length == 0)
            {
                throw new ArgumentException("At least one unstarted thread should be created.", nameof(threadFactory));
            }

            if (threads.Any(static thread => thread == null || (thread.ThreadState & ThreadState.Unstarted) == 0))
            {

View on GitHub (pinned to c236dd0f93)

Solutions

  1. If you maintain a custom processing server, supply a non-null threadFactory (e.g. start => new[] { new Thread(start) { IsBackground = true } }).
  2. Use the public BackgroundJobServer API instead of constructing internal dispatchers directly, so the factory is provided for you.
  3. Ensure any test helper that builds a BackgroundDispatcher passes a valid factory that returns unstarted threads.

Example fix

// before
var d = new BackgroundDispatcher(execution, action, state, null);

// after
Func<ThreadStart, IEnumerable<Thread>> factory =
    start => new[] { new Thread(start) { IsBackground = true } };
var d = new BackgroundDispatcher(execution, action, state, factory);
Defensive patterns

Strategy: validation

Validate before calling

if (threadFactory == null) throw new ArgumentNullException(nameof(threadFactory));
Func<ThreadStart, IEnumerable<Thread>> factory =
    start => new[] { new Thread(start) { IsBackground = true } };

Prevention

When it happens

Trigger: Constructing a BackgroundDispatcher with a null threadFactory. This is an internal API normally invoked by the Hangfire processing machinery (BackgroundJobServer/processing server) with a framework-supplied factory; a null factory would only arise from a custom/derived processing server or a reflection-based instantiation that did not supply one.

Common situations: A custom processing server that manually instantiates BackgroundDispatcher with a null factory; a test that constructs the dispatcher without a thread factory; a reflection/serialization path that omits the argument. End users of BackgroundJobServer do not pass this argument directly.

Related errors


AI-assisted analysis of HangfireIO/Hangfire@c236dd0f93 (2026-08-13). Data as JSON: /api/errors/319a4981cab5034b. Report an issue: GitHub.