dotnet/reactive · error · ArgumentNullException
threadFactory (Parameter 'threadFactory')
Error message
threadFactory (Parameter 'threadFactory')
What it means
The NewThreadScheduler(Func<ThreadStart, Thread>) constructor throws ArgumentNullException when threadFactory is null. The factory is the core mechanism this scheduler uses to create a thread per unit of work, so without it the scheduler cannot function at all.
Solutions
- Pass a valid factory such as 'static ThreadStart ts => new Thread(ts)' to the constructor.
- Use NewThreadScheduler.Default (or Scheduler.NewThread) instead of constructing manually.
- Guard the factory argument with ArgumentNullException.ThrowIfNull before constructing.
- Fix configuration resolution so the factory delegate is not null.
Example fix
// before
var scheduler = new NewThreadScheduler(config.ThreadFactory); // null when unset
// after
var scheduler = config.ThreadFactory is null
? NewThreadScheduler.Default
: new NewThreadScheduler(config.ThreadFactory); Defensive patterns
Strategy: validation
Validate before calling
if (threadFactory == null)
threadFactory = ts => new Thread(ts); // or use NewThreadScheduler.Default Type guard
bool HasThreadFactory(Func<ThreadStart, Thread> f) => f is not null;
Try / catch
try
{
var s = new NewThreadScheduler(threadFactory);
}
catch (ArgumentNullException ex) when (ex.ParamName == "threadFactory")
{
var s = NewThreadScheduler.Default;
} Prevention
- Prefer NewThreadScheduler.Default or Scheduler.NewThread over manual construction.
- Centralize thread-factory creation in one factory method that guarantees non-null.
- Fail fast at startup if configuration supplying the factory is missing.
When it happens
Trigger: Calling new NewThreadScheduler(null), or NewThreadScheduler.Default-style paths where a custom factory resolved from configuration/lambda is null.
Common situations: Building a scheduler from settings where the factory delegate is read as null; refactoring away Scheduler.NewThread internals; passing a method group that fails to bind (e.g. wrong overload) yielding null after a ternary.
Related errors
- action (Parameter 'action')
- comparer (Parameter 'comparer')
- scheduler (Parameter 'scheduler')
- action (Parameter 'action')
- scheduler (Parameter 'scheduler')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/d0815b8a210c91a9.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Concurrency/NewThreadScheduler.cs:39
/// </summary>
public NewThreadScheduler()
: this(action => new Thread(action))
{
}
/// <summary>
/// Gets an instance of this scheduler that uses the default Thread constructor.
/// </summary>
public static NewThreadScheduler Default => Instance.Value;
/// <summary>
/// Creates an object that schedules each unit of work on a separate thread.
/// </summary>
/// <param name="threadFactory">Factory function for thread creation.</param>
/// <exception cref="ArgumentNullException"><paramref name="threadFactory"/> is <c>null</c>.</exception>
public NewThreadScheduler(Func<ThreadStart, Thread> threadFactory)
{
_threadFactory = threadFactory ?? throw new ArgumentNullException(nameof(threadFactory));
}
/// <summary>
/// Schedules an action to be executed after dueTime.
/// </summary>
/// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam>
/// <param name="state">State passed to the action to be executed.</param>
/// <param name="action">Action to be executed.</param>
/// <param name="dueTime">Relative time after which to execute the action.</param>
/// <returns>The disposable object used to cancel the scheduled action (best effort).</returns>
/// <exception cref="ArgumentNullException"><paramref name="action"/> is <c>null</c>.</exception>
public override IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
{
if (action == null)
{
throw new ArgumentNullException(nameof(action));
}
View on GitHub (pinned to 94b5d5ab91)