{"record":{"id":"18395efc8756c866","repo":"dotnet/reactive","slug":"value-cannot-be-null-parameter-threadfactory","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'threadFactory')","messagePattern":"Value cannot be null\\. \\(Parameter 'threadFactory'\\)","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Concurrency/EventLoopScheduler.cs","lineNumber":96,"sourceCode":"\n        #region Constructors\n\n        /// <summary>\n        /// Creates an object that schedules units of work on a designated thread.\n        /// </summary>\n        public EventLoopScheduler()\n            : this(static a => new Thread(a) { Name = \"Event Loop \" + Interlocked.Increment(ref _counter), IsBackground = true })\n        {\n        }\n\n        /// <summary>\n        /// Creates an object that schedules units of work on a designated thread, using the specified factory to control thread creation options.\n        /// </summary>\n        /// <param name=\"threadFactory\">Factory function for thread creation.</param>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"threadFactory\"/> is <c>null</c>.</exception>\n        public EventLoopScheduler(Func<ThreadStart, Thread> threadFactory)\n        {\n            _threadFactory = threadFactory ?? throw new ArgumentNullException(nameof(threadFactory));\n            _stopwatch = ConcurrencyAbstractionLayer.Current.StartStopwatch();\n\n            _gate = new object();\n\n            _evt = new SemaphoreSlim(0);\n            _queue = new SchedulerQueue<TimeSpan>();\n            _readyList = new Queue<ScheduledItem<TimeSpan>>();\n\n            ExitIfEmpty = false;\n        }\n\n        #endregion\n\n        #region Properties\n\n        /// <summary>\n        /// Indicates whether the event loop thread is allowed to quit when no work is left. If new work\n        /// is scheduled afterwards, a new event loop thread is created. This property is used by the","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Concurrency/EventLoopScheduler.cs#L78-L114","documentation":"The EventLoopScheduler constructor requires a Func<ThreadStart, Thread> factory used to create the scheduler's dedicated thread. Passing null triggers the null-coalescing throw expression, raising ArgumentNullException before the stopwatch, gate, semaphore, and queue are initialized.","triggerScenarios":"new EventLoopScheduler(null) or new EventLoopScheduler(someFactoryVariable) where the factory variable is null, commonly from DI resolution or a config-supplied factory that failed to load.","commonSituations":"Container registrations missing the thread factory, reflection-based instantiation supplying null, or code migrated from the parameterless EventLoopScheduler() overload that accidentally passes null instead.","solutions":["Pass a concrete factory, e.g. new EventLoopScheduler(ts => new Thread(ts) { IsBackground = true, Name = \"MyEventLoop\" }).","Use the parameterless EventLoopScheduler() overload if default thread creation is acceptable.","Fix DI registration so a non-null factory is provided; validate it at composition time."],"exampleFix":"// before\nvar scheduler = new EventLoopScheduler(factory); // factory null\n\n// after\nvar scheduler = new EventLoopScheduler(ts => new Thread(ts) { IsBackground = true, Name = \"EventLoop\" });","handlingStrategy":"validation","validationCode":"if (threadFactory is null)\n    throw new ArgumentNullException(nameof(threadFactory));\nvar scheduler = new EventLoopScheduler(threadFactory);","typeGuard":"bool IsValid(Func<ThreadStart, Thread>? f) => f is not null;","tryCatchPattern":"try { var s = new EventLoopScheduler(threadFactory); } catch (ArgumentNullException ex) when (ex.ParamName == \"threadFactory\") { /* fall back to new EventLoopScheduler() or fix DI registration */ }","preventionTips":["Standardize on a factory like ts => new Thread(ts) { IsBackground = true }","Verify DI container registrations for EventLoopScheduler dependencies","Use the parameterless overload when custom thread creation is unnecessary"],"tags":["null-argument","event-loop","constructor"],"backgroundTag":"null-argument","analyzedSha":"94b5d5ab912789f5abe9a72138a25bbd716fe59c","analyzedAt":"2026-09-15T02:26:24.759Z","contentChangedAt":"2026-09-15T02:26:24.759Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}