{"record":{"id":"8d0000ef2c8ad353","repo":"dotnet/reactive","slug":"the-current-thread-has-no-dispatcher-associated-with-it","errorCode":null,"errorMessage":"The current thread has no Dispatcher associated with it.","messagePattern":"The current thread has no Dispatcher associated with it\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Platforms/Desktop/Concurrency/DispatcherScheduler.cs","lineNumber":33,"sourceCode":"    /// This scheduler type is typically used indirectly through the <see cref=\"Linq.DispatcherObservable.ObserveOnDispatcher{TSource}(IObservable{TSource})\"/> and <see cref=\"Linq.DispatcherObservable.SubscribeOnDispatcher{TSource}(IObservable{TSource})\"/> methods that use the Dispatcher on the calling thread.\n    /// </remarks>\n    public class DispatcherScheduler : LocalScheduler, ISchedulerPeriodic\n    {\n        /// <summary>\n        /// Gets the scheduler that schedules work on the current <see cref=\"System.Windows.Threading.Dispatcher\"/>.\n        /// </summary>\n        [Obsolete(Constants_WindowsThreading.OBSOLETE_INSTANCE_PROPERTY)]\n        public static DispatcherScheduler Instance => new(System.Windows.Threading.Dispatcher.CurrentDispatcher);\n\n        /// <summary>\n        /// Gets the scheduler that schedules work on the <see cref=\"System.Windows.Threading.Dispatcher\"/> for the current thread.\n        /// </summary>\n        public static DispatcherScheduler Current\n        {\n            get\n            {\n                var dispatcher = System.Windows.Threading.Dispatcher.FromThread(Thread.CurrentThread)\n                    ?? throw new InvalidOperationException(Strings_WindowsThreading.NO_DISPATCHER_CURRENT_THREAD);\n                return new DispatcherScheduler(dispatcher);\n            }\n        }\n\n        /// <summary>\n        /// Constructs a <see cref=\"DispatcherScheduler\"/> that schedules units of work on the given <see cref=\"System.Windows.Threading.Dispatcher\"/>.\n        /// </summary>\n        /// <param name=\"dispatcher\"><see cref=\"DispatcherScheduler\"/> to schedule work on.</param>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"dispatcher\"/> is <c>null</c>.</exception>\n        public DispatcherScheduler(System.Windows.Threading.Dispatcher dispatcher)\n        {\n            Dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));\n            Priority = System.Windows.Threading.DispatcherPriority.Normal;\n\n        }\n\n        /// <summary>\n        /// Constructs a <see cref=\"DispatcherScheduler\"/> that schedules units of work on the given <see cref=\"System.Windows.Threading.Dispatcher\"/> at the given priority.","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Platforms/Desktop/Concurrency/DispatcherScheduler.cs#L15-L51","documentation":"DispatcherScheduler.Current lazily creates a scheduler bound to the Dispatcher of the calling thread. WPF Dispatchers are thread-affine; if the current thread has none (e.g. a thread-pool, task, or console thread), Dispatcher.FromThread returns null and the property throws InvalidOperationException with the NO_DISPATCHER_CURRENT_THREAD message.","triggerScenarios":"Accessing DispatcherScheduler.Current from a background thread (Task.Run, ThreadPool, new Thread, Rx SubscribeOnDefaults threads) or before/without a WPF Dispatcher running — e.g. in a console app or unit test with no Dispatcher installed.","commonSituations":"Calling DispatcherScheduler.Current inside an Rx operator's lambda running on a scheduler pool thread; using it in non-WPF apps that referenced the WindowsThreading package by mistake; tests without a DispatcherFrame/Dispatcher pump.","solutions":["Capture DispatcherScheduler.Current (or Dispatcher.CurrentDispatcher) on the UI thread first, then pass that instance to ObserveOn/SubscribeOn for use on background threads.","Construct the scheduler explicitly with a known dispatcher: new DispatcherScheduler(Application.Current.Dispatcher).","Fall back gracefully when no dispatcher exists: use ObserveOn(Scheduler.Default) or post via SynchronizationContext.Current instead."],"exampleFix":"// before (runs on pool thread → throws)\nsource.ObserveOn(DispatcherScheduler.Current).Subscribe(x => ...);\n// after: capture on UI thread\nvar uiScheduler = new DispatcherScheduler(Application.Current.Dispatcher);\nsource.ObserveOn(uiScheduler).Subscribe(x => ...);","handlingStrategy":"fallback","validationCode":"var dispatcher = System.Windows.Threading.Dispatcher.FromThread(Thread.CurrentThread);\nvar scheduler = dispatcher != null ? new DispatcherScheduler(dispatcher) : Scheduler.Default;","typeGuard":"static bool HasCurrentDispatcher() => System.Windows.Threading.Dispatcher.FromThread(Thread.CurrentThread) != null;","tryCatchPattern":"try { sched = DispatcherScheduler.Current; } catch (InvalidOperationException) { sched = Scheduler.Default; // no dispatcher on this thread }","preventionTips":["Capture the UI dispatcher once on the UI thread and pass it to background code","Never access DispatcherScheduler.Current from Task.Run/thread-pool lambdas","Prefer ObserveOn(SynchronizationContext.Current) which degrades gracefully"],"tags":["dotnet","wpf","dispatcher","thread-affinity"],"backgroundTag":"invalid-state-transition","analyzedSha":"94b5d5ab912789f5abe9a72138a25bbd716fe59c","analyzedAt":"2026-09-15T02:26:24.759Z","contentChangedAt":"2026-09-15T02:26:24.759Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}