stride3d/stride · error · ArgumentException

Value must be null for action != (MemberActionType.SetValue…

Error message

Value must be null for action != (MemberActionType.SetValue || MemberPathAction.CollectionAdd)

What it means

MemberPath.Apply() validates that the optional 'value' argument is only supplied for actions that can carry a payload: ValueSet and CollectionAdd. For all other actions (CollectionRemove, DictionaryRemove, etc.) a non-null value is meaningless, so the library rejects it with ArgumentException. This keeps the path-mutation API from silently ignoring values it cannot use.

Solutions

  1. Pass null as the value argument for non-set actions: Apply(root, MemberPathAction.CollectionRemove, null).
  2. Remove the item via the path itself — for CollectionRemove the last path item identifies the element; no value is needed.
  3. If you actually need to supply a value, switch the action to MemberPathAction.ValueSet (member assignment) or MemberPathAction.CollectionAdd (element insert).

Example fix

// before
path.Apply(root, MemberPathAction.CollectionRemove, itemToRemove);
// after
path.Apply(root, MemberPathAction.CollectionRemove, null);
Defensive patterns

Strategy: validation

Validate before calling

bool valueAllowed = action is MemberPathAction.ValueSet or MemberPathAction.CollectionAdd;
if (!valueAllowed && value != null)
    throw new ArgumentException($"value must be null for action {action}");
path.Apply(root, action, value);

Type guard

static bool ActionAcceptsValue(MemberPathAction a) => a is MemberPathAction.ValueSet or MemberPathAction.CollectionAdd;

Try / catch

try { path.Apply(root, action, value); }
catch (ArgumentException ex) when (ex.Message.Contains("Value must be null")) { /* pass null or switch action */ }

Prevention

When it happens

Trigger: Calling memberPath.Apply(root, MemberPathAction.CollectionRemove, someObject) or Apply(root, MemberPathAction.DictionaryRemove, someObject) with a non-null value instead of Apply(root, action, null).

Common situations: Developers reusing a generic Apply wrapper that always passes a value; copying code from a SetValue call site and changing only the action enum; assuming Remove actions accept the item to remove as the value parameter.

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/0e6ceb8e4324ee29. Report an issue: GitHub.

Appendix: source

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

    /// <summary>
    /// Pops the last item from the current path.
    /// </summary>
    public void Pop()
    {
        if (items.Count > 0)
        {
            items.RemoveAt(items.Count - 1);
        }
    }

    public bool Apply(object rootObject, MemberPathAction actionType, object? value)
    {
        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))

View on GitHub (pinned to 96fad776d2)