{"record":{"id":"8f2ec950db5d4c63","repo":"stride3d/stride","slug":"game-must-be-assigned-before-base-finishedlaunching","errorCode":null,"errorMessage":"Game must be assigned before base.FinishedLaunching.","messagePattern":"Game must be assigned before base\\.FinishedLaunching\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Games/Starter/StrideApplicationDelegate.cs","lineNumber":27,"sourceCode":"\nnamespace Stride.Starter\n{\n    /// <summary>\n    /// UIApplicationDelegate base for Stride iOS games. Subclass and assign <see cref=\"Game\"/>\n    /// in <c>FinishedLaunching</c> before calling <c>base.FinishedLaunching</c>; the base creates\n    /// an SDL window + iOS GameContext and schedules <see cref=\"GameBase.Run\"/> on the next\n    /// main-loop tick so launch finishes before the (blocking) game loop takes over.\n    /// </summary>\n    public class StrideApplicationDelegate : UIApplicationDelegate\n    {\n        protected GameBase Game { get; set; }\n\n        private Window sdlWindow;\n\n        public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)\n        {\n            if (Game == null)\n                throw new InvalidOperationException(\"Game must be assigned before base.FinishedLaunching.\");\n\n            sdlWindow = new Window(\"Stride\");\n\n            // Game.Run blocks; iOS needs FinishedLaunching to return for launch to complete.\n            BeginInvokeOnMainThread(() =>\n            {\n                try { Game.Run(new GameContextiOS(sdlWindow)); }\n                finally { sdlWindow?.Dispose(); sdlWindow = null; }\n            });\n\n            return true;\n        }\n\n        public override void WillTerminate(UIApplication application)\n        {\n            Game?.Exit();\n            Game?.Dispose();\n            Game = null;","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Games/Starter/StrideApplicationDelegate.cs#L9-L45","documentation":"StrideApplicationDelegate.FinishedLaunching (iOS/UIKit lifecycle callback) requires the static Game property to be assigned before base lifecycle processing continues, throwing otherwise. The delegate needs a live Game to create the SDL window and start the game loop on the main thread; launching without one cannot proceed.","triggerScenarios":"AppDelegate overrides FinishedLaunching and calls base.FinishedLaunching(application, launchOptions) (or lets the base run) without setting Game = new MyGame() beforehand.","commonSituations":"Forgetting the Game assignment in a custom AppDelegate, reordering startup code so FinishedLaunching runs before the field initializer, or template refactors that moved Game creation after the lifecycle callback.","solutions":["Assign the Game property before FinishedLaunching executes — typically in the AppDelegate constructor or as a field initializer: Game = new MyGame();","If creation is deferred, override FinishedLaunching and assign Game as the first statement before calling base.","Verify the iOS bootstrap order so no UIKit callback reaches the delegate before Game is set."],"exampleFix":"// before\npublic override bool FinishedLaunching(UIApplication app, NSDictionary options)\n{\n    return base.FinishedLaunching(app, options); // Game is null\n}\n// after\npublic override bool FinishedLaunching(UIApplication app, NSDictionary options)\n{\n    Game = Game ?? new MyGame();\n    return base.FinishedLaunching(app, options);\n}","handlingStrategy":"validation","validationCode":"public override bool FinishedLaunching(UIApplication app, NSDictionary options)\n{\n    if (Game is null) Game = new MyGame();\n    return base.FinishedLaunching(app, options);\n}","typeGuard":"bool ReadyToLaunch() => Game != null;","tryCatchPattern":"try { return base.FinishedLaunching(app, options); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Game must be assigned\"))\n{\n    Game = new MyGame();\n    return base.FinishedLaunching(app, options);\n}","preventionTips":["Initialize Game in the AppDelegate constructor or a field initializer so it exists before any UIKit callback.","Keep the Stride iOS template's ordering when customizing the delegate.","Never defer Game creation until after lifecycle callbacks."],"tags":["ios","initialization","lifecycle","null-reference"],"backgroundTag":"null-argument","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"}