stride3d/stride · critical · InvalidOperationException

The StrideAssetsViewModel class can be instanced only once.

Error message

The StrideAssetsViewModel class can be instanced only once.

What it means

StrideAssetsViewModel is a process-wide singleton for the asset editor session. Its constructor throws InvalidOperationException if a static Instance already exists, because duplicate instances would create two competing views of the same asset session. Note the throw happens AFTER constructing CodeViewModel but the TaskCompletionSource `instance.TrySetResult(this)` runs after the check, so a second construction aborts before satisfying the instance task.

Solutions

  1. Reuse the existing instance via `StrideAssetsViewModel.InstanceTask` (await it) instead of constructing a new one.
  2. Guard construction with `if (StrideAssetsViewModel.Instance == null)` before instantiating.
  3. In tests, create the view model in a fresh AppDomain/assembly-reload context or accept it as a shared fixture.
  4. For multi-session needs, refactor to hold per-session view models instead of relying on the singleton.

Example fix

// before
var vm = new StrideAssetsViewModel(session);
// after
var vm = await StrideAssetsViewModel.InstanceTask; // or: if (StrideAssetsViewModel.Instance != null) return;
Defensive patterns

Strategy: fallback

Validate before calling

if (StrideAssetsViewModel.Instance != null)
    return await StrideAssetsViewModel.InstanceTask;
var vm = new StrideAssetsViewModel(session);

Prevention

When it happens

Trigger: Constructing `new StrideAssetsViewModel(...)` a second time in the same AppDomain, e.g. re-running editor startup code, creating a second assets view/window, or unit tests that build the view model per test without resetting the static Instance.

Common situations: Opening a second editor window for the same session; plugin/extension code initializing the assets view model independently; test fixtures that don't isolate static state; hot-reload scenarios re-running initialization.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/ff15a0cc460023fc. Report an issue: GitHub.

Appendix: source

Thrown at sources/editor/Stride.Assets.Presentation/ViewModel/StrideAssetsViewModel.cs:21

using System;
using System.Threading.Tasks;
using Stride.Core.Assets.Editor.ViewModel;
using Stride.Core.Presentation.ViewModels;

namespace Stride.Assets.Presentation.ViewModel
{
    public class StrideAssetsViewModel : DispatcherViewModel
    {
        private static readonly TaskCompletionSource<StrideAssetsViewModel> instance = new TaskCompletionSource<StrideAssetsViewModel>();

        public StrideAssetsViewModel(SessionViewModel session) : base(session.ServiceProvider)
        {
            Session = session;

            Code = new CodeViewModel(this);

            if (Instance != null)
                throw new InvalidOperationException($"The {nameof(StrideAssetsViewModel)} class can be instanced only once.");

            instance.TrySetResult(this);
            Instance = this;
        }

        public static Task<StrideAssetsViewModel> InstanceTask => instance.Task;

        public static StrideAssetsViewModel Instance { get; private set; }

        public SessionViewModel Session { get; }

        public CodeViewModel Code { get; }
    }
}

View on GitHub (pinned to 96fad776d2)