{"record":{"id":"ca5ba007bfacf3d2","repo":"stride3d/stride","slug":"the-current-thread-was-expected-to-be-different-from-the","errorCode":null,"errorMessage":"The current thread was expected to be different from the dispatcher thread.","messagePattern":"The current thread was expected to be different from the dispatcher thread\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/presentation/Stride.Core.Presentation.Wpf/View/DispatcherService.cs","lineNumber":120,"sourceCode":"        {\n            var tcs = new TaskCompletionSource<TResult>();\n            dispatcher.InvokeAsync(async () => tcs.SetResult(await task()), DispatcherPriority.Normal, token);\n            return tcs.Task;\n        }\n\n        /// <inheritdoc/>\n        public bool CheckAccess()\n        {\n            return Thread.CurrentThread == dispatcher.Thread;\n        }\n\n        /// <inheritdoc/>\n        public void EnsureAccess(bool inDispatcherThread = true)\n        {\n            if (inDispatcherThread && Thread.CurrentThread != dispatcher.Thread)\n                throw new InvalidOperationException(\"The current thread was expected to be the dispatcher thread.\");\n            if (!inDispatcherThread && Thread.CurrentThread == dispatcher.Thread)\n                throw new InvalidOperationException(\"The current thread was expected to be different from the dispatcher thread.\");\n        }\n    }\n}\n","sourceCodeStart":102,"sourceCodeEnd":124,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/presentation/Stride.Core.Presentation.Wpf/View/DispatcherService.cs#L102-L124","documentation":"DispatcherService.EnsureAccess has an inverted mode: when called with inDispatcherThread=false it asserts the current thread is NOT the dispatcher thread. It throws InvalidOperationException if the code is unexpectedly running on the dispatcher thread, used to guard operations designed to run in the background.","triggerScenarios":"Calling EnsureAccess(false) from code that ended up executing on the dispatcher thread, e.g. a background helper invoked synchronously from a UI event handler.","commonSituations":"Long-running work accidentally scheduled on the UI thread causing freezes; refactoring that changed a background invocation into a synchronous call without updating the assertion.","solutions":["Move the guarded work onto a background thread (Task.Run, dispatcher.InvokeAsync with background priority, or a worker)","Remove the EnsureAccess(false) assertion if the operation is now legitimate on the dispatcher thread","Restructure the call chain so background helpers are not invoked synchronously from UI handlers"],"exampleFix":"// before\nDoBackgroundWork(); // called directly on dispatcher thread, EnsureAccess(false) throws\n// after\nawait Task.Run(DoBackgroundWork); // runs off the dispatcher thread","handlingStrategy":"try-catch","validationCode":"if (!dispatcherService.CheckAccess()) RunBackground(); else await Task.Run(RunBackground);","typeGuard":"bool OffDispatcher(DispatcherService s) => !s.CheckAccess();","tryCatchPattern":"try { s.EnsureAccess(false); } catch (InvalidOperationException ex) when (ex.Message.Contains(\"different from the dispatcher thread\")) { await Task.Run(Work); }","preventionTips":["Schedule background helpers with Task.Run","Don't call background-only APIs synchronously from UI handlers","Recheck thread assertions after refactors"],"tags":["wpf","threading","dispatcher"],"backgroundTag":"thread-interrupted","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}