{"record":{"id":"6b2f67b3f72ef9b6","repo":"stride3d/stride","slug":"update-requested-without-a-launcher-window-cannot-continue","errorCode":null,"errorMessage":"Update requested without a Launcher Window. Cannot continue!","messagePattern":"Update requested without a Launcher Window\\. Cannot continue!","errorType":"exception","errorClass":"ApplicationException","httpStatus":null,"severity":"error","filePath":"sources/launcher/Stride.Launcher/Services/SelfUpdater.cs","lineNumber":169,"sourceCode":"\n        // Check to see if an update is needed\n        if (package is null || version >= new PackageVersion(package.Version.Version, package.Version.SpecialVersion))\n        {\n            return;\n        }\n\n        // Display progress window\n        await dispatcher.InvokeAsync(() =>\n        {\n            selfUpdateWindow = new();\n            selfUpdateWindow.LockWindow();\n            if (Application.Current is App { MainWindow: Window window })\n            {\n                _ = selfUpdateWindow.ShowDialog(window); // we don't await on purpose here\n            }\n            else\n            {\n                throw new ApplicationException(\"Update requested without a Launcher Window. Cannot continue!\");\n            }\n        }, cancellationToken);\n\n        var movedFiles = new List<string>();\n\n        // Download package\n        var installedPackage = await store.InstallPackage(package.Id, package.Version, package.TargetFrameworks, null);\n\n        // Copy files from tools\\ to the current directory\n        var inputFiles = installedPackage.GetFiles();\n\n        // TODO: We should get list of previous files from nuspec (store it as a resource and open it with NuGet API maybe?)\n        // TODO: For now, we deal only with the App.config file since we won't be able to fix it afterward.\n        var exeLocation = Program.GetExecutablePath();\n        var exeDirectory = Path.GetDirectoryName(exeLocation)!;\n        const string directoryRoot = \"tools/\"; // Important!: this is matching where files are store in the nuspec\n        try\n        {","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/launcher/Stride.Launcher/Services/SelfUpdater.cs#L151-L187","documentation":"The Stride Launcher's self-update flow shows the self-update window as a dialog anchored to the launcher's main window. If Application.Current is not an App with a non-null MainWindow (or no WPF Application exists at all), SelfUpdater refuses to continue because there is no owner window for the modal dialog. The exception is thrown inside the update Task, so it surfaces as a faulted task rather than synchronously.","triggerScenarios":"Calling SelfUpdate (which calls UpdateLauncherFiles) while the launcher has no initialized MainWindow: the window is still loading, was closed, the App instance is not the derived App type, or the method is invoked from a headless/CLI context where Application.Current is null.","commonSituations":"Launching the update very early at startup before MainWindow is assigned; triggering an auto-update after the main window was closed; running the updater in tests or automation without a WPF Application; a custom App class not matching the 'App { MainWindow: Window }' pattern.","solutions":["Ensure the launcher's MainWindow is created, assigned, and shown before invoking SelfUpdate","Guard the update trigger: only allow self-update when Application.Current is App with a non-null MainWindow","If no window exists, surface a normal window-less update path or prompt the user to reopen the launcher","Catch the faulted task in the caller and log a user-friendly message instead of crashing"],"exampleFix":"// before\nselfUpdateButton.Command = UpdateNow; // can run before window ready\n// after\nif (Application.Current is App { MainWindow: Window window } && window.IsLoaded)\n    UpdateNow();\nelse\n    MessageBox.Show(\"Cannot update: launcher window is not available.\");","handlingStrategy":"validation","validationCode":"bool canSelfUpdate = Application.Current is App { MainWindow: Window { IsLoaded: true } };","typeGuard":"static bool HasLauncherWindow() => Application.Current is App { MainWindow: Window window };","tryCatchPattern":"try { await SelfUpdate(); } catch (ApplicationException ex) when (ex.Message.Contains(\"Launcher Window\")) { ShowUpdateUnavailableMessage(); }","preventionTips":["Only expose update commands after the window is loaded","Add a can-execute guard on the update command checking MainWindow","Test self-update in headless/automation mode to catch ordering issues","Never close the main window while an update is pending"],"tags":["wpf","updater","null-reference","window-lifecycle"],"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"}