stride3d/stride · error · ArgumentException

Invalid path [ ] for action [ ]. Expecting last path to be…

Error message

Invalid path [{0}] for action [{1}]. Expecting last path to be a collection item

What it means

MemberPathAction.CollectionAdd operates on the element referenced by the LAST path segment, which must be a CollectionPathItem. Apply() pattern-matches the final item and throws ArgumentException when the path ends on a plain member, dictionary item, or array item instead.

Solutions

  1. Push a collection item segment so the path ends inside the collection before calling CollectionAdd.
  2. If you intended to replace the whole collection, use MemberPathAction.ValueSet with the last segment being the member.
  3. Use MemberPath.FromMemberPath / CreateIntermediateObjects helpers to construct the correctly shaped path.

Example fix

// before
var path = new MemberPath();
path.Push(type.GetProperty("Items"));
path.Apply(root, MemberPathAction.CollectionAdd, newItem);
// after
var path = new MemberPath();
path.Push(type.GetProperty("Items"));
path.PushCollectionItem(); // ensure last segment is a collection item
path.Apply(root, MemberPathAction.CollectionAdd, newItem);
Defensive patterns

Strategy: validation

Validate before calling

var last = path.Items[^1];
if (action == MemberPathAction.CollectionAdd && last is not CollectionPathItem)
    throw new InvalidOperationException("CollectionAdd requires a collection-item path segment.");

Type guard

static bool CanCollectionAdd(MemberPath p) => p.Items.Count > 0 && p.Items[^1] is CollectionPathItem;

Try / catch

try { path.Apply(root, MemberPathAction.CollectionAdd, item); }
catch (ArgumentException ex) when (ex.Message.Contains("Expecting last path to be a collection item")) { /* push a collection-item segment */ }

Prevention

When it happens

Trigger: Calling Apply(root, MemberPathAction.CollectionAdd, value) on a path whose last pushed segment is a MemberPathItem (e.g. path 'MyList' itself rather than an item within it) or a DictionaryPathItem.

Common situations: Pushing only the collection's member descriptor but not a collection-item segment before calling CollectionAdd; reusing a path built for ValueSet of the collection property and switching the action to CollectionAdd.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at sources/core/Stride.Core.Reflection/MemberPath.cs:240

        ArgumentNullException.ThrowIfNull(rootObject);
        if (rootObject.GetType().IsValueType) throw new ArgumentException("Value type for root objects are not supported", nameof(rootObject));
        if (actionType != MemberPathAction.ValueSet && actionType != MemberPathAction.CollectionAdd && value != null)
        {
            throw new ArgumentException("Value must be null for action != (MemberActionType.SetValue || MemberPathAction.CollectionAdd)");
        }

        if (items == null || items.Count == 0)
        {
            throw new InvalidOperationException("This instance doesn't contain any path. Use Push() methods to populate paths");
        }

        var lastItem = items[^1];
        switch (actionType)
        {
            case MemberPathAction.CollectionAdd:
                if (lastItem is not CollectionPathItem)
                {
                    throw new ArgumentException("Invalid path [{0}] for action [{1}]. Expecting last path to be a collection item".ToFormat(this, actionType));
                }
                break;
            case MemberPathAction.CollectionRemove:
                if (lastItem is not (CollectionPathItem or ArrayPathItem))
                {
                    throw new ArgumentException("Invalid path [{0}] for action [{1}]. Expecting last path to be a collection/array item".ToFormat(this, actionType));
                }
                break;

            case MemberPathAction.DictionaryRemove:
                if (lastItem is not DictionaryPathItem)
                {
                    throw new ArgumentException("Invalid path [{0}] for action [{1}]. Expecting last path to be a dictionary item".ToFormat(this, actionType));
                }
                break;
        }

        var stack = stackTLS;

View on GitHub (pinned to 96fad776d2)