{"record":{"id":"58dae1918729d308","repo":"dotnet/maui","slug":"bindableobject-was-not-instantiated-on-a-thread-wi","errorCode":null,"errorMessage":"BindableObject was not instantiated on a thread with a dispatcher nor does the current application have a dispatcher.","messagePattern":"BindableObject was not instantiated on a thread with a dispatcher nor does the current application have a dispatcher\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Controls/src/Core/DispatcherExtensions.cs","lineNumber":47,"sourceCode":"\t\t\t{\n\t\t\t\tif (appMauiContext.Services.GetOptionalApplicationDispatcher() is IDispatcher appDispatcherServiceDispatcher)\n\t\t\t\t\treturn appDispatcherServiceDispatcher;\n\n\t\t\t\t// If BO is of type Application then check for its Dispatcher\n\t\t\t\tif (appMauiContext.Services.GetService<IDispatcher>() is IDispatcher appHandlerDispatcher)\n\t\t\t\t\treturn appHandlerDispatcher;\n\t\t\t}\n\n\t\t\t// try looking on the static app\n\t\t\t// We don't include Application because Application.Dispatcher will call\n\t\t\t// `FindDispatcher` if it's _dispatcher property isn't initialized so this\n\t\t\t// could cause a Stack Overflow Exception\n\t\t\tif (bindableObject is not Application &&\n\t\t\t\tApplication.Current?.Dispatcher is IDispatcher appDispatcher)\n\t\t\t\treturn appDispatcher;\n\n\t\t\t// no dispatchers found at all\n\t\t\tthrow new InvalidOperationException(\"BindableObject was not instantiated on a thread with a dispatcher nor does the current application have a dispatcher.\");\n\t\t}\n\n\t\tpublic static void DispatchIfRequired(this IDispatcher? dispatcher, Action action)\n\t\t{\n\t\t\tdispatcher = EnsureDispatcher(dispatcher);\n\t\t\tif (dispatcher.IsDispatchRequired)\n\t\t\t{\n\t\t\t\tdispatcher.Dispatch(action);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\taction();\n\t\t\t}\n\t\t}\n\n\t\tpublic static Task DispatchIfRequiredAsync(this IDispatcher? dispatcher, Action action)\n\t\t{\n\t\t\tdispatcher = EnsureDispatcher(dispatcher);","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/dotnet/maui/blob/f377ff1c5ee04d334d8a925f50c83a6b7afddf03/src/Controls/src/Core/DispatcherExtensions.cs#L29-L65","documentation":"FindDispatcher throws InvalidOperationException when no dispatcher can be located for a BindableObject: the object's own dispatcher is null, Dispatcher.GetForCurrentThread() returns null, the handler-level dispatcher is null, and Application.Current?.Dispatcher is null (or the object is an Application itself, which is skipped to avoid recursion). The framework needs a dispatcher to marshal work to the UI thread.","triggerScenarios":"Constructing a BindableObject on a background thread with no UI dispatcher, in a headless/test host, or before Application.Current is set, then calling an extension that needs dispatching (e.g. DispatchIfRequired).","commonSituations":"Unit tests instantiating Controls without a dispatcher; creating BindableObjects in Task.Run before the app is initialized; library code used outside a normal app lifecycle.","solutions":["Create the BindableObject on the UI/main thread where Dispatcher.GetForCurrentThread() is available.","Ensure Application.Current is initialized before using Controls off the UI thread.","In tests, provide a mock/foreground dispatcher or use the dispatcher test helpers."],"exampleFix":"// before\nawait Task.Run(() => { var btn = new Button(); btn.Dispatcher; }); // no dispatcher on bg thread\n\n// after\nawait MainThread.InvokeOnMainThreadAsync(() =>\n{\n    var btn = new Button();\n    _ = btn.Dispatcher; // dispatcher available\n});","handlingStrategy":"validation","validationCode":"// Confirm a dispatcher exists before using Controls off the UI thread.\nstatic bool HasDispatcher(BindableObject o) =>\n    o.Dispatcher is not null\n    || Dispatcher.GetForCurrentThread() is not null\n    || (Application.Current?.Dispatcher is not null);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Create BindableObjects on the main/UI thread.","Ensure Application.Current is set before off-thread Control use.","In tests, install a dispatcher (e.g. via test harness) before instantiating Controls."],"tags":["dispatcher","threading","invalidoperation","uithread"],"backgroundTag":null,"analyzedSha":"f377ff1c5ee04d334d8a925f50c83a6b7afddf03","analyzedAt":"2026-08-13T14:26:18.069Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}