stride3d/stride · error · InvalidOperationException
The current thread was expected to be different from the…
Error message
The current thread was expected to be different from the dispatcher thread.
What it means
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.
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
Example fix
// before DoBackgroundWork(); // called directly on dispatcher thread, EnsureAccess(false) throws // after await Task.Run(DoBackgroundWork); // runs off the dispatcher thread
Defensive patterns
Strategy: try-catch
Validate before calling
if (!dispatcherService.CheckAccess()) RunBackground(); else await Task.Run(RunBackground);
Type guard
bool OffDispatcher(DispatcherService s) => !s.CheckAccess();
Try / catch
try { s.EnsureAccess(false); } catch (InvalidOperationException ex) when (ex.Message.Contains("different from the dispatcher thread")) { await Task.Run(Work); } Prevention
- Schedule background helpers with Task.Run
- Don't call background-only APIs synchronously from UI handlers
- Recheck thread assertions after refactors
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- A dispatcher lock must be created from a different thread…
- The current thread was expected to be the dispatcher thread.
- This method must be invoked from the dispatcher thread
- Trying to lock while another thread owns the lock.
- Trying to unlock while another thread owns the lock.
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/ca5ba007bfacf3d2.
Report an issue: GitHub.
Appendix: source
Thrown at sources/presentation/Stride.Core.Presentation.Wpf/View/DispatcherService.cs:120
{
var tcs = new TaskCompletionSource<TResult>();
dispatcher.InvokeAsync(async () => tcs.SetResult(await task()), DispatcherPriority.Normal, token);
return tcs.Task;
}
/// <inheritdoc/>
public bool CheckAccess()
{
return Thread.CurrentThread == dispatcher.Thread;
}
/// <inheritdoc/>
public void EnsureAccess(bool inDispatcherThread = true)
{
if (inDispatcherThread && Thread.CurrentThread != dispatcher.Thread)
throw new InvalidOperationException("The current thread was expected to be the dispatcher thread.");
if (!inDispatcherThread && Thread.CurrentThread == dispatcher.Thread)
throw new InvalidOperationException("The current thread was expected to be different from the dispatcher thread.");
}
}
}
View on GitHub (pinned to 96fad776d2)