stride3d/stride · error · ObjectDisposedException
This controller has already been disposed.
Error message
This controller has already been disposed.
What it means
EnsureNotDestroyed throws ObjectDisposedException when EditorGameController.IsDestroyed is true. After Destroy() completes, all game-side resources (game thread, form, services) are gone, so any further use — StartGame, GetService, GetMousePositionInScene, etc. — is invalid and guarded by this method called from all public entry points.
Solutions
- Check controller.IsDestroyed before every use and reacquire the controller from the editor when the asset is reopened.
- Catch ObjectDisposedException around controller calls in long-lived background code.
- Subscribe to the asset editor's close event to stop using the controller at the right time.
Example fix
// before
controller.GetService<IMyService>().DoWork();
// after
if (!controller.IsDestroyed)
controller.GetService<IMyService>().DoWork(); Defensive patterns
Strategy: try-catch
Validate before calling
if (controller.IsDestroyed)
return; // controller already disposed Type guard
bool IsAlive(EditorGameControllerBase c) => !c.IsDestroyed;
Try / catch
try { controller.GetService<T>(); }
catch (ObjectDisposedException) { /* reacquire controller from the reopened asset editor */ } Prevention
- Clear cached controller references on asset close
- Use weak references or lifetime-scoped services for background jobs
- Guard all long-lived background work with IsDestroyed checks
When it happens
Trigger: Calling any public controller method (StartGame, GetService<T>, Destroy again, GetMousePositionInScene, TriggerActiveRenderStageReevaluation, FindGameSidePart) after the editor asset was closed and the controller disposed.
Common situations: Holding a stale controller reference after closing/reopening an asset editor; background jobs or timers that outlive the asset session; double teardown logic calling Destroy twice.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- This controller is beeing disposed.
- this
- Trying to dispose a lock that has already been released.
- The default profile cannot be unloaded
- Unable to unload the current profile.
AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14).
Data as JSON: /api/errors/9605025855766013.
Report an issue: GitHub.
Appendix: source
Thrown at sources/editor/Stride.Assets.Presentation/AssetEditors/GameEditor/Services/EditorGameController.cs:392
{
throw new NotSupportedException();
}
/// <inheritdoc/>
TResult IDispatcherService.Invoke<TResult>(Func<TResult> callback)
{
throw new NotSupportedException();
}
/// <summary>
/// Checks whether this controller has been disposed, and throws an <see cref="ObjectDisposedException"/> if it is the case.
/// </summary>
/// <param name="name">The name to supply to the <see cref="ObjectDisposedException"/>.</param>
protected void EnsureNotDestroyed(string name = null)
{
if (IsDestroyed)
{
throw new ObjectDisposedException(name ?? nameof(EditorGameController<TEditorGame>), "This controller has already been disposed.");
}
}
protected virtual void InitializeServices([NotNull] EditorGameServiceRegistry services)
{
services.Add(new EditorGameDebugService());
services.Add(RecoveryService = new EditorGameRecoveryService(Editor) { IsActive = true });
}
private void SceneGameRunThread()
{
// Create the form from this thread
GameForm = new EmbeddedGameForm
{
TopLevel = false,
Visible = false,
};
windowHandle = GameForm.Handle;View on GitHub (pinned to 96fad776d2)