{"record":{"id":"9605025855766013","repo":"stride3d/stride","slug":"this-controller-has-already-been-disposed","errorCode":null,"errorMessage":"This controller has already been disposed.","messagePattern":"This controller has already been disposed\\.","errorType":"exception","errorClass":"ObjectDisposedException","httpStatus":null,"severity":"error","filePath":"sources/editor/Stride.Assets.Presentation/AssetEditors/GameEditor/Services/EditorGameController.cs","lineNumber":392,"sourceCode":"        {\n            throw new NotSupportedException();\n        }\n\n        /// <inheritdoc/>\n        TResult IDispatcherService.Invoke<TResult>(Func<TResult> callback)\n        {\n            throw new NotSupportedException();\n        }\n\n        /// <summary>\n        /// Checks whether this controller has been disposed, and throws an <see cref=\"ObjectDisposedException\"/> if it is the case.\n        /// </summary>\n        /// <param name=\"name\">The name to supply to the <see cref=\"ObjectDisposedException\"/>.</param>\n        protected void EnsureNotDestroyed(string name = null)\n        {\n            if (IsDestroyed)\n            {\n                throw new ObjectDisposedException(name ?? nameof(EditorGameController<TEditorGame>), \"This controller has already been disposed.\");\n            }\n        }\n\n        protected virtual void InitializeServices([NotNull] EditorGameServiceRegistry services)\n        {\n            services.Add(new EditorGameDebugService());\n            services.Add(RecoveryService = new EditorGameRecoveryService(Editor) { IsActive = true });\n        }\n\n        private void SceneGameRunThread()\n        {\n            // Create the form from this thread\n            GameForm = new EmbeddedGameForm\n            {\n                TopLevel = false,\n                Visible = false,\n            };\n            windowHandle = GameForm.Handle;","sourceCodeStart":374,"sourceCodeEnd":410,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/editor/Stride.Assets.Presentation/AssetEditors/GameEditor/Services/EditorGameController.cs#L374-L410","documentation":"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.","triggerScenarios":"Calling any public controller method (StartGame, GetService<T>, Destroy again, GetMousePositionInScene, TriggerActiveRenderStageReevaluation, FindGameSidePart) after the editor asset was closed and the controller disposed.","commonSituations":"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.","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."],"exampleFix":"// before\ncontroller.GetService<IMyService>().DoWork();\n// after\nif (!controller.IsDestroyed)\n    controller.GetService<IMyService>().DoWork();","handlingStrategy":"try-catch","validationCode":"if (controller.IsDestroyed)\n    return; // controller already disposed","typeGuard":"bool IsAlive(EditorGameControllerBase c) => !c.IsDestroyed;","tryCatchPattern":"try { controller.GetService<T>(); }\ncatch (ObjectDisposedException) { /* reacquire controller from the reopened asset editor */ }","preventionTips":["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"],"tags":["disposed","objectdisposedexception","lifecycle","game-editor"],"backgroundTag":"invalid-state-transition","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"}