dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'control')

Error message

Value cannot be null. (Parameter 'control')

What it means

The ControlScheduler constructor stores the Windows Forms Control on which work will be invoked via control.BeginInvoke, so a null control is rejected immediately with ArgumentNullException. ControlScheduler cannot function without a control because it uses the control's handle/thread to marshal execution.

Solutions

  1. Pass a valid, constructed Control instance (e.g. the form or a control on it).
  2. Check for null before constructing: if (control == null) throw/log instead.
  3. Ensure InitializeComponent has run so designer control fields are assigned before scheduler creation.

Example fix

// before
var scheduler = new ControlScheduler(_myControl); // _myControl null before InitializeComponent
// after
InitializeComponent();
if (_myControl == null) throw new InvalidOperationException("control not initialized");
var scheduler = new ControlScheduler(_myControl);
Defensive patterns

Strategy: validation

Validate before calling

if (control == null || control.IsDisposed) throw new InvalidOperationException("A live WinForms control is required");
var scheduler = new ControlScheduler(control);

Type guard

static bool HasControl(Control c) => c is not null && !c.IsDisposed;

Try / catch

try { var s = new ControlScheduler(control); } catch (ArgumentNullException ex) when (ex.ParamName == "control") { /* log missing control dependency */ }

Prevention

When it happens

Trigger: new ControlScheduler(null), or passing a Control field/property that is null (e.g. a form control accessed before InitializeComponent or from a context where the control reference was never assigned).

Common situations: Constructor injection where the WinForms control dependency was not registered; using this.SomeControl in a control whose designer field is not yet initialized; unit tests constructing the scheduler without a real control.

Related errors


AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15). Data as JSON: /api/errors/46b1b9c245d36220. Report an issue: GitHub.

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Platforms/Desktop/Concurrency/ControlScheduler.cs:28

{
    /// <summary>
    /// Represents an object that schedules units of work on the message loop associated with a Windows Forms control.
    /// </summary>
    public class ControlScheduler : LocalScheduler, ISchedulerPeriodic
    {
        private readonly Control _control;

        /// <summary>
        /// Constructs a ControlScheduler that schedules units of work on the message loop associated with the specified Windows Forms control.
        /// </summary>
        /// <param name="control">Windows Forms control to get the message loop from.</param>
        /// <exception cref="ArgumentNullException"><paramref name="control"/> is null.</exception>
        /// <remarks>
        /// This scheduler type is typically used indirectly through the <see cref="Linq.ControlObservable.ObserveOn{TSource}"/> and <see cref="Linq.ControlObservable.SubscribeOn{TSource}"/> method overloads that take a Windows Forms control.
        /// </remarks>
        public ControlScheduler(Control control)
        {
            _control = control ?? throw new ArgumentNullException(nameof(control));
        }

        /// <summary>
        /// Gets the control associated with the ControlScheduler.
        /// </summary>
        public Control Control => _control;

        /// <summary>
        /// Schedules an action to be executed on the message loop associated with the control.
        /// </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>
        /// <returns>The disposable object used to cancel the scheduled action (best effort).</returns>
        /// <exception cref="ArgumentNullException"><paramref name="action"/> is null.</exception>
        public override IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
        {
            if (action == null)

View on GitHub (pinned to 94b5d5ab91)