stride3d/stride · error · NodePresenterException

An error occurred while removing an item to the node, see…

Error message

An error occurred while removing an item to the node, see the inner exception for more information.

What it means

ItemNodePresenter.RemoveItem(value, index) wraps any exception thrown by Container.IndexedTarget(Index).Remove(value, index) in a NodePresenterException. The library centralizes collection-removal failures into NodePresenterException; diagnose via InnerException. Typical inner causes are an index/key that no longer exists, an item that is not present, or removal not being supported by the underlying collection.

Solutions

  1. Catch NodePresenterException and inspect InnerException for the exact cause.
  2. Verify the item still exists at the given index (Container.Retrieve(Index)) before removing, and refresh the presenter if the collection changed.
  3. Check that the collection type actually supports removal (not an array or read-only wrapper).
  4. Use the current NodeIndex from the presenter/UI selection rather than a cached one.

Example fix

// before
presenter.RemoveItem(item, cachedIndex); // index stale after reload -> wrapped exception
// after
var current = (IList)containerNode.Retrieve();
int i = current.IndexOf(item);
if (i >= 0)
    presenter.RemoveItem(item, new NodeIndex(i));
Defensive patterns

Strategy: validation

Validate before calling

var target = presenter.Container.IndexedTarget(presenter.Index);
if (target == null || !target.IsEnumerable) return;
var current = target.Retrieve();
bool exists = index.IsInt
    ? index.Int < ((IList)current).Count
    : current is System.Collections.IDictionary d && d.Contains(index.Value);
if (!exists) throw new InvalidOperationException("Item no longer exists at this index; refresh the presenter.");

Type guard

static bool CanRemove(ItemNodePresenter p, NodeIndex index)
    => p.Container.IndexedTarget(p.Index)?.IsEnumerable == true
       && index != NodeIndex.Empty;

Try / catch

try
{
    itemPresenter.RemoveItem(value, index);
}
catch (NodePresenterException ex)
{
    // stale index or unsupported removal
    RefreshPresenter();
    logger.Warn(ex.InnerException, "Remove failed; presenter refreshed");
}

Prevention

When it happens

Trigger: Calling ItemNodePresenter.RemoveItem(value, index) when the NodeIndex is stale (item already removed or collection shifted), the key does not exist in a dictionary, the value does not match the item stored at that index, or the underlying collection (array, IReadOnlyList) has no working Remove implementation.

Common situations: Editor UI removing a row after the model was reloaded or reordered elsewhere (stale NodeIndex); removing by a dictionary key that was renamed; calling RemoveItem on a node whose collection became read-only after a serialization round-trip.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at sources/presentation/Stride.Core.Presentation.Quantum/Presenters/ItemNodePresenter.cs:114

        }
        catch (Exception e)
        {
            throw new NodePresenterException("An error occurred while adding an item to the node, see the inner exception for more information.", e);
        }
    }

    public override void RemoveItem(object value, NodeIndex index)
    {
        if (Container.IndexedTarget(Index)?.IsEnumerable != true)
            throw new NodePresenterException($"{nameof(MemberNodePresenter)}.{nameof(AddItem)} cannot be invoked on members that are not collection.");

        try
        {
            Container.IndexedTarget(Index).Remove(value, index);
        }
        catch (Exception e)
        {
            throw new NodePresenterException("An error occurred while removing an item to the node, see the inner exception for more information.", e);
        }
    }

    public override NodeAccessor GetNodeAccessor()
    {
        return new NodeAccessor(Container, Index);
    }

    private void OnItemChanging(object? sender, ItemChangeEventArgs e)
    {
        if (IsValidChange(e))
            RaiseValueChanging(e.NewValue);
    }

    private void OnItemChanged(object? sender, ItemChangeEventArgs e)
    {
        if (IsValidChange(e))
        {

View on GitHub (pinned to 96fad776d2)