{"record":{"id":"0aac72d5531ae50d","repo":"stride3d/stride","slug":"the-sessionviewmodel-class-can-be-instanced-only-once","errorCode":null,"errorMessage":"The SessionViewModel class can be instanced only once.","messagePattern":"The SessionViewModel class can be instanced only once\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/editor/Stride.Core.Assets.Editor/ViewModel/SessionViewModel.cs","lineNumber":563,"sourceCode":"            var documentationService = ServiceProvider.Get<UserDocumentationService>();\n            foreach (var packageAssembly in LocalPackages.SelectMany(p => p.LoadedAssemblies))\n            {\n                if (packageAssembly.Assembly != null)\n                    Task.Run(() => documentationService.CacheAssemblyDocumentation(packageAssembly.Assembly));\n            }\n        }\n\n        private SessionViewModel(IViewModelServiceProvider serviceProvider, ILogger logger, [NotNull] PackageSession session, [NotNull] EditorViewModel editor)\n            : base(serviceProvider)\n        {\n            if (editor == null) throw new ArgumentNullException(nameof(editor));\n            if (editor.Session != null) throw new InvalidOperationException(\"Unable to have two sessions at the same time\");\n\n            Editor = editor;\n            this.session = session;\n\n            if (Instance != null)\n                throw new InvalidOperationException(\"The SessionViewModel class can be instanced only once.\");\n\n            Instance = this;\n\n            // Initialize the dirtiable manager for all our dirtiable objects\n            undoRedoService = ServiceProvider.Get<IUndoRedoService>();\n\n            // Gather all data from plugins\n            PluginService.RegisterSession(this, logger);\n\n            // Initialize the undo/redo debug view model\n            undoRedoStackPage = EditorDebugTools.CreateUndoRedoDebugPage(undoRedoService, \"Undo/redo stack\");\n            ActionHistory = new ActionHistoryViewModel(this);\n\n            // Initialize the node container used for asset properties\n            AssetNodeContainer = new SessionNodeContainer(this) { NodeBuilder = { NodeFactory = new AssetNodeFactory() } };\n\n            // Initialize the view model that will manage the properties of the assets selected on the main asset view\n            AssetViewProperties = new SessionObjectPropertiesViewModel(this);","sourceCodeStart":545,"sourceCodeEnd":581,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/editor/Stride.Core.Assets.Editor/ViewModel/SessionViewModel.cs#L545-L581","documentation":"SessionViewModel enforces a singleton pattern via a static Instance field. The constructor throws InvalidOperationException if Instance is already set, because the class can only be instantiated once per editor process. After construction it assigns Instance = this.","triggerScenarios":"Constructing (via CreateInstance) a second SessionViewModel while the previous instance is still alive and Instance is non-null.","commonSituations":"Opening a second editor session or reloading a session without disposing the first; unit tests that construct SessionViewModel multiple times without cleanup.","solutions":["Dispose/close the existing SessionViewModel (which should null Instance) before creating a new one.","Keep a single app-wide SessionViewModel and reuse it instead of constructing new ones.","In tests, reset the singleton (dispose and clear Instance) in test teardown.","Catch InvalidOperationException to detect an existing session and route to the existing instance."],"exampleFix":"// before\nvar newSession = SessionViewModel.CreateInstance(provider, logger, session, editor); // Instance still set\n// after\noldSession.Dispose(); // clears Instance\nvar newSession = SessionViewModel.CreateInstance(provider, logger, session, editor);","handlingStrategy":"validation","validationCode":"if (SessionViewModel.Instance != null)\n    throw new InvalidOperationException(\"SessionViewModel already exists; dispose it first\");","typeGuard":null,"tryCatchPattern":"try { session = SessionViewModel.CreateInstance(sp, log, ps, editor); }\ncatch (InvalidOperationException) { session = SessionViewModel.Instance; /* reuse singleton */ }","preventionTips":["Treat SessionViewModel as a singleton app-wide","Dispose in teardown to clear Instance","In tests, reset the singleton between test cases"],"tags":["csharp","singleton","lifecycle"],"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"}