dotnet/reactive · error · ArgumentNullException
dispatcher
Error message
dispatcher
What it means
SubscribeOn(source, dispatcher) throws ArgumentNullException when the dispatcher parameter is null. The dispatcher is required to construct the CoreDispatcherScheduler used to marshal subscription (and disposal) work onto the UI thread. The library validates both arguments eagerly at call time.
Solutions
- Capture the dispatcher on the UI thread at startup (e.g. during OnLaunched) and pass that cached instance instead of resolving it at call time.
- Use CoreDispatcherScheduler.Current only on UI threads; on background threads capture the UI dispatcher once and store it in a service.
- Validate before calling: if (dispatcher == null) throw or fall back to SubscribeOn(TaskPoolScheduler.Default).
- Check that the object whose Dispatcher you pass is not null itself (null dependencyObject.Dispatcher is impossible here since the argument is typed CoreDispatcher, but passing null literals happens in refactors).
Example fix
// before source.SubscribeOn(Window.Current?.Dispatcher) // null on background thread // after private static CoreDispatcher _uiDispatcher; public static void Init(CoreDispatcher d) => _uiDispatcher = d; // called on UI thread source.SubscribeOn(_uiDispatcher)
Defensive patterns
Strategy: validation
Validate before calling
if (dispatcher == null)
throw new InvalidOperationException("Capture the UI dispatcher on the UI thread before calling SubscribeOn");
source.SubscribeOn(dispatcher).Subscribe(handler); Type guard
bool HasDispatcher(CoreDispatcher d) => d != null;
Try / catch
try { source.SubscribeOn(dispatcher).Subscribe(handler); }
catch (ArgumentNullException ex) when (ex.ParamName == "dispatcher")
{ source.SubscribeOn(DefaultScheduler.Instance).Subscribe(handler); } Prevention
- Capture Window.Current.Dispatcher once during app startup, not at call time.
- Never resolve Window.Current from background/thread-pool threads.
- Inject the dispatcher as a service rather than reaching for globals.
- Prefer SubscribeOn(dispatcher) over object-derived overloads to make the null point explicit.
When it happens
Trigger: Calling observable.SubscribeOn(null), or passing a dispatcher obtained from a null object — e.g. Window.Current is null in background threads/non-UI contexts, or a control's Dispatcher property read after the element was detached in edge cases.
Common situations: Calling SubscribeOn from a background thread where CoreWindow/Window.Current is unavailable; caching a Window reference that is null when the app runs in a hosted/background context; accidentally swapping argument order or passing an uninitialized field.
Related errors
- source
- dependencyObject
- Value cannot be null. (Parameter 'source')
- nameof(observableFactory)
- nameof(observableFactoryAsync)
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/f888fa8b690819be.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Platforms/WinRT/Linq/CoreDispatcherObservable.cs:178
/// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
/// <param name="source">Source sequence.</param>
/// <param name="dispatcher">Dispatcher whose associated message loop is used to perform subscription and unsubscription actions on.</param>
/// <returns>The source sequence whose subscriptions and unsubscriptions happen on the specified dispatcher.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="dispatcher"/> is null.</exception>
/// <remarks>
/// Only the side-effects of subscribing to the source sequence and disposing subscriptions to the source sequence are run on the specified dispatcher.
/// In order to invoke observer callbacks on the specified dispatcher, e.g. to render results in a control, use <see cref="CoreDispatcherObservable.ObserveOn{TSource}(IObservable{TSource}, CoreDispatcher)"/>.
/// </remarks>
public static IObservable<TSource> SubscribeOn<TSource>(this IObservable<TSource> source, CoreDispatcher dispatcher)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (dispatcher == null)
{
throw new ArgumentNullException(nameof(dispatcher));
}
return Synchronization.SubscribeOn(source, new CoreDispatcherScheduler(dispatcher));
}
/// <summary>
/// Wraps the source sequence in order to run its subscription and unsubscription logic on the specified dispatcher.
/// </summary>
/// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
/// <param name="source">Source sequence.</param>
/// <param name="dispatcher">Dispatcher whose associated message loop is used to perform subscription and unsubscription actions on.</param>
/// <param name="priority">Priority to schedule work items at.</param>
/// <returns>The source sequence whose subscriptions and unsubscriptions happen on the specified dispatcher.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="dispatcher"/> is null.</exception>
/// <remarks>
/// Only the side-effects of subscribing to the source sequence and disposing subscriptions to the source sequence are run on the specified dispatcher.
/// In order to invoke observer callbacks on the specified dispatcher, e.g. to render results in a control, use <see cref="CoreDispatcherObservable.ObserveOn{TSource}(IObservable{TSource}, CoreDispatcher, CoreDispatcherPriority)"/>.
/// </remarks>View on GitHub (pinned to 94b5d5ab91)