stride3d/stride · error · InvalidOperationException

Unable to reach the game-side instance

Error message

Unable to reach the game-side instance

What it means

GameEditorChangePropagator.Initialize resolves the game-side counterpart of an asset part by asking the controller (on the game thread) to FindGameSidePart for the part's AbsoluteId. If the lookup returns null — the game-side entity/object does not exist — the propagator cannot link asset and game nodes and throws InvalidOperationException.

Solutions

  1. Ensure the asset is saved/instanced before starting the game preview so game-side parts exist for every asset part.
  2. Wrap propagator creation in try/catch and re-create the propagator when the game scene reloads.
  3. Verify the part's AbsoluteId (AssetId + part Id) matches an actual instance in the scene; fix custom tooling that fabricates ids.

Example fix

// before
var gameSide = await controller.InvokeAsync(() => controller.FindGameSidePart(partId));
// after
var gameSide = await controller.InvokeAsync(() => controller.FindGameSidePart(partId));
if (gameSide == null)
    logger.Warning($"Part {partId} not instanced game-side; skipping propagation");
Defensive patterns

Strategy: try-catch

Validate before calling

var exists = await controller.InvokeAsync(() => controller.FindGameSidePart(partId) != null);
if (!exists) return; // part not instanced game-side

Try / catch

try { await propagator.Initialize(part); }
catch (InvalidOperationException ex) when (ex.Message.Contains("game-side instance")) { logger.Warning($"Skipping uninstanced part {partId}"); }

Prevention

When it happens

Trigger: The asset-side instance (e.g. an entity inside a prefab/composable scene) has no corresponding game-side instance at propagation start: the part was added or renamed between the game start snapshot and propagator initialization, or the part id does not exist in the running scene.

Common situations: Editing a prefab while its instance is live in the game preview; parts created programmatically without being instantiated game-side; race where the game scene loaded a stale version of the scene.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at sources/editor/Stride.Assets.Presentation/AssetEditors/GameEditor/ViewModels/GameEditorChangePropagator.cs:77

            listener.ValueChanged -= AssetSideNodeChanged;
            listener.ItemChanged -= AssetSideNodeChanged;

            running = false;
            // This will resume the propagator task if it's awaiting, and allow it to complete.
            propagatorQueue.Post(null);
        }

        public void NotifyGameSidePartAdded()
        {
            gameSideReady.SetResult(0);
        }

        private async Task Initialize([NotNull] TAssetPart assetSideInstance)
        {
            var partId = new AbsoluteId(Owner.Id.AssetId, assetSideInstance.Id);
            var gameSideInstance = await Editor.Controller.InvokeAsync(() => Editor.Controller.FindGameSidePart(partId));
            if (gameSideInstance == null)
                throw new InvalidOperationException("Unable to reach the game-side instance");

            using (await DispatcherLock.Lock(true, Editor.Controller, Editor.Dispatcher))
            {
                Editor.Controller.Logger.Debug($"Initial linking for part {assetSideInstance.Id}");
                var assetNode = (IAssetNode)Editor.NodeContainer.GetNode(assetSideInstance);
                var gameNode = Editor.Controller.GameSideNodeContainer.GetOrCreateNode(gameSideInstance);
                gameObjectLinker.LinkGraph(assetNode, gameNode);
            }
        }

        private static void LinkNode(IGraphNode assetNode, IGraphNode gameNode)
        {
            var node = (IAssetNode)assetNode;
            node.SetContent(GameSideContentKey, gameNode);
        }

        private void AssetSideNodeChanged(object sender, INodeChangeEventArgs e)
        {

View on GitHub (pinned to 96fad776d2)