stride3d/stride · error · InvalidOperationException

The given assetSidePart.Id does not correspond to any…

Error message

The given assetSidePart.Id does not correspond to any existing part.

What it means

UIEditorController.RemovePart throws this InvalidOperationException when assetSidePart.Id cannot be resolved to a game-side UIElement via FindPart. Removing an element with no game-side mirror is treated as a logic error rather than a no-op, because it indicates the asset-side and game-side trees have diverged.

Solutions

  1. Check that the part id exists in the view model tree before calling RemovePart.
  2. Make deletion idempotent on the caller side: track already-removed ids and skip repeats.
  3. Refresh id references after undo/redo or asset reload.
  4. Ensure AddPart succeeded before attempting to remove the same part.

Example fix

// before
controller.RemovePart(part, parent);
// after
if (removedIds.Add(part.Id))
    controller.RemovePart(part, parent);
Defensive patterns

Strategy: validation

Validate before calling

bool partExists = viewModel.TreeRoot.Flatten().Any(e => e.Id == part.Id);
if (!partExists) return; // nothing to remove, skip

Type guard

UIElementViewModel FindLivePart(Id id) => viewModel.TreeRoot.Flatten().FirstOrDefault(e => e.Id == id);

Try / catch

try { controller.RemovePart(part, parent); }
catch (InvalidOperationException ex) when (ex.Message.Contains("does not correspond to any existing part")) { /* already removed; ignore */ }

Prevention

When it happens

Trigger: Calling RemovePart with an id that was already removed, never added, or belongs to another asset; RemovePart invoked twice for the same element (duplicate delete events); game-side creation previously failed so the mirror entry is missing.

Common situations: Delete handlers firing twice, deletion during undo/redo replay with stale ids, scripts caching element ids across asset reloads.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

Thrown at sources/editor/Stride.Assets.Presentation/AssetEditors/UIEditor/Services/UIEditorController.cs:256

                        }
                        GameSideNodeContainer.GetNode(contentControl)[nameof(contentControl.Content)].Update(gameSidePart);
                    }
                }
            });
        }

        /// <inheritdoc />
        public override Task RemovePart([NotNull] UIHierarchyItemViewModel parent, UIElement assetSidePart)
        {
            EnsureAssetAccess();

            return InvokeAsync(() =>
            {
                Logger.Debug($"Removing element {assetSidePart.Id} from game-side scene");
                var partId = new AbsoluteId(AssetId.Empty, assetSidePart.Id);
                var part = (UIElement)FindPart(partId);
                if (part == null)
                    throw new InvalidOperationException($"The given {nameof(assetSidePart.Id)} does not correspond to any existing part.");

                var parentId = (parent as UIElementViewModel)?.Id;
                if (parentId == null)
                {
                    RootElements.Remove(assetSidePart.Id);
                }
                else
                {
                    var parentElement = (UIElement)FindPart(parentId.Value);
                    if (parentElement == null)
                        throw new InvalidOperationException($"The given {nameof(parentId)} does not correspond to any existing part.");

                    var panel = parentElement as Panel;
                    var contentControl = parentElement as ContentControl;
                    if (panel != null)
                    {
                        var i = panel.Children.IndexOf(part);
                        GameSideNodeContainer.GetNode(panel.Children).Remove(part, new NodeIndex(i));

View on GitHub (pinned to 96fad776d2)