{"record":{"id":"857851ef6956814b","repo":"PrismLibrary/Prism","slug":"resources-eventaggregatornotconstructedonuithread","errorCode":null,"errorMessage":"Resources.EventAggregatorNotConstructedOnUIThread","messagePattern":"Resources\\.EventAggregatorNotConstructedOnUIThread","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Prism.Events/PubSubEvent.cs","lineNumber":85,"sourceCode":"        /// If not using a WeakReference (<paramref name=\"keepSubscriberReferenceAlive\"/> is <see langword=\"true\" />), the user must explicitly call Unsubscribe for the event when disposing the subscriber in order to avoid memory leaks or unexpected behavior.\n        /// <para/>\n        /// The PubSubEvent collection is thread-safe.\n        /// </remarks>\n        public virtual SubscriptionToken Subscribe(Action action, ThreadOption threadOption, bool keepSubscriberReferenceAlive)\n        {\n            IDelegateReference actionReference = new DelegateReference(action, keepSubscriberReferenceAlive);\n\n            EventSubscription subscription;\n            switch (threadOption)\n            {\n                case ThreadOption.PublisherThread:\n                    subscription = new EventSubscription(actionReference);\n                    break;\n                case ThreadOption.BackgroundThread:\n                    subscription = new BackgroundEventSubscription(actionReference);\n                    break;\n                case ThreadOption.UIThread:\n                    if (SynchronizationContext == null) throw new InvalidOperationException(Resources.EventAggregatorNotConstructedOnUIThread);\n                    subscription = new DispatcherEventSubscription(actionReference, SynchronizationContext);\n                    break;\n                default:\n                    subscription = new EventSubscription(actionReference);\n                    break;\n            }\n\n            return InternalSubscribe(subscription);\n        }\n\n        /// <summary>\n        /// Publishes the <see cref=\"PubSubEvent\"/>.\n        /// </summary>\n        public virtual void Publish()\n        {\n            InternalPublish();\n        }\n","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/PrismLibrary/Prism/blob/358118cd640d9a22ff8cf21c8ad197fa038b7990/src/Prism.Events/PubSubEvent.cs#L67-L103","documentation":"PubSubEvent.Subscribe with ThreadOption.UIThread requires the EventAggregator to have captured a SynchronizationContext at construction. Prism throws InvalidOperationException with Resources.EventAggregatorNotConstructedOnUIThread when SynchronizationContext is null, because it cannot marshal the handler to the UI thread.","triggerScenarios":"Calling event.Subscribe(handler, ThreadOption.UIThread) on an EventAggregator that was constructed on a background thread (or in a context without a SynchronizationContext, e.g. some console/test/worker scenarios).","commonSituations":"Creating the EventAggregator in a background worker or before the UI framework initializes, unit tests running without a synchronization context, Xamarin/MAUI apps where the aggregator is built in a non-UI bootstrap path.","solutions":["Construct the EventAggregator on the UI thread so SynchronizationContext.Current is captured","Subscribe with ThreadOption.BackgroundThread or PublisherThread if UI marshaling is not required","Explicitly set SynchronizationContext.Current before constructing the aggregator (e.g. capture the main thread's context)","Register the EventAggregator via DI on the UI thread during app startup"],"exampleFix":"// before (background thread)\nvar aggregator = new EventAggregator();\nmyEvent.Subscribe(handler, ThreadOption.UIThread); // throws\n// after\nDevice.BeginInvokeOnMainThread(() => aggregator.GetEvent<MyEvent>().Subscribe(handler, ThreadOption.UIThread));","handlingStrategy":"try-catch","validationCode":"if (SynchronizationContext.Current == null)\n    throw new InvalidOperationException(\"Subscribe with ThreadOption.UIThread requires a SynchronizationContext; construct the EventAggregator on the UI thread.\");","typeGuard":"bool CanSubscribeOnUIThread(EventAggregator ea) => ea.GetType() != null && SynchronizationContext.Current != null;","tryCatchPattern":"try\n{\n    myEvent.Subscribe(handler, ThreadOption.UIThread);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"UI\"))\n{\n    myEvent.Subscribe(handler, ThreadOption.BackgroundThread); // fallback\n}","preventionTips":["Create the EventAggregator on the main/UI thread during app startup","Never new-up an EventAggregator inside Task.Run or a worker thread","In tests, set SynchronizationContext.Current or use BackgroundThread"],"tags":["prism","eventaggregator","threading","ui-thread"],"backgroundTag":"missing-required-config","analyzedSha":"358118cd640d9a22ff8cf21c8ad197fa038b7990","analyzedAt":"2026-09-15T15:00:31.079Z","contentChangedAt":"2026-09-15T15:00:31.079Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}