{"record":{"id":"46f125c5106d6de6","repo":"stride3d/stride","slug":"this-code-must-not-be-executed-in-the-game-thread","errorCode":null,"errorMessage":"This code must not be executed in the game thread.","messagePattern":"This code must not be executed in the game thread\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/editor/Stride.Assets.Presentation/AssetEditors/GameEditor/Services/EditorGameController.cs","lineNumber":363,"sourceCode":"        /// Verifies that the current thread is the game thread.\n        /// </summary>\n        /// <returns><c>True</c> if the current thread is the game thread, <c>False</c> otherwise.</returns>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public bool CheckGameAccess()\n        {\n            return Thread.CurrentThread == sceneGameThread;\n        }\n\n        /// <summary>\n        /// Ensures that the current thread is the game thread. This method will throw an exception if it is not the case.\n        /// </summary>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void EnsureGameAccess(bool inGameThread = true)\n        {\n            if (inGameThread && Thread.CurrentThread != sceneGameThread)\n                throw new InvalidOperationException(\"This code must be executed in the game thread.\");\n            if (!inGameThread && Thread.CurrentThread == sceneGameThread)\n                throw new InvalidOperationException(\"This code must not be executed in the game thread.\");\n        }\n\n        /// <inheritdoc/>\n        bool IDispatcherService.CheckAccess() => CheckGameAccess();\n\n        /// <inheritdoc/>\n        void IDispatcherService.EnsureAccess(bool inDispatcherThread) => EnsureGameAccess(inDispatcherThread);\n\n        /// <inheritdoc/>\n        void IDispatcherService.Invoke(Action callback)\n        {\n            throw new NotSupportedException();\n        }\n\n        /// <inheritdoc/>\n        TResult IDispatcherService.Invoke<TResult>(Func<TResult> callback)\n        {\n            throw new NotSupportedException();","sourceCodeStart":345,"sourceCodeEnd":381,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/editor/Stride.Assets.Presentation/AssetEditors/GameEditor/Services/EditorGameController.cs#L345-L381","documentation":"The inverse guard of EnsureGameAccess: called with inGameThread: false, it asserts the code is NOT running on the sceneGameThread. Operations that must not touch the game thread from within itself (e.g. marshaling work that would deadlock, or asset-side-only mutations) throw InvalidOperationException when invoked from the game thread.","triggerScenarios":"Calling an API that internally invokes EnsureGameAccess(false) (e.g. EnsureAccess with opposite polarity) while already executing on sceneGameThread — typically game-thread code trying to synchronously call back into asset-side or dispatcher code.","commonSituations":"Game-side event handlers or callbacks making synchronous calls into services that forbid game-thread execution; recursive Invoke patterns that would deadlock the game loop.","solutions":["Move the offending call off the game thread, e.g. schedule it via Editor.Dispatcher.InvokeAsync.","If already in async code, use Task.Run or configure continuations off the game thread.","Check the called method's documentation for thread requirements and respect the asset-side/game-side split."],"exampleFix":"// before (inside game-thread callback)\neditor.Dispatcher.Invoke(() => UpdateAssetSide()); // deadlock risk / forbidden\n// after\nTask.Run(() => editor.Dispatcher.InvokeAsync(() => UpdateAssetSide()));","handlingStrategy":"validation","validationCode":"if (Thread.CurrentThread == controller.GameThread)\n    throw new InvalidOperationException(\"This call must be marshaled off the game thread.\");","typeGuard":null,"tryCatchPattern":"try { AssetSideOperation(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"must not be executed\")) { await editor.Dispatcher.InvokeAsync(AssetSideOperation); }","preventionTips":["Never make synchronous calls back into asset/dispatcher code from game-thread callbacks","Schedule cross-side work via Dispatcher.InvokeAsync or Task.Run","Document thread requirements on your service APIs"],"tags":["threading","thread-affinity","deadlock","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"}