stride3d/stride · error · InvalidOperationException

The property [ ] of type [ ] has no setter.

Error message

The property [{Name}] of type [{DeclaringType.Name}] has no setter.

What it means

PropertyDescriptor.Set invokes the property's setter via reflection. If the property is read-only (no setMethod), it throws InvalidOperationException naming the property and declaring type, because the value cannot be written.

Solutions

  1. Check PropertyDescriptor.HasSetter (or the property has a public setter) before calling Set
  2. Make the property writable (add a setter) if it is legitimately mutable
  3. Route the write to the backing field or a method instead of the read-only property

Example fix

// before
propDesc.Set(entity, newValue); // read-only property
// after
if (propDesc.HasSetter) propDesc.Set(entity, newValue);
Defensive patterns

Strategy: validation

Validate before calling

if (!propDesc.HasSetter) throw new NotSupportedException($"{propDesc.Name} is read-only");

Try / catch

try { propDesc.Set(obj, value); }
catch (InvalidOperationException) { /* property is read-only; write backing field or skip */ }

Prevention

When it happens

Trigger: Calling Set on a get-only property descriptor; serializing/assigning into read-only properties via the property system; editor/data-binding code attempting to write an inferred read-only property.

Common situations: Game studio/property grid editing a computed or get-only property; reflection-based data loading that tries to restore values into read-only properties; auto-generated descriptors where the backing set method wasn't found.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at sources/core/Stride.Core.Reflection/MemberDescriptors/PropertyDescriptor.cs:49

    /// </summary>
    /// <value>The property information.</value>
    public PropertyInfo PropertyInfo { get; }

    public override Type Type => PropertyInfo.PropertyType;

    public sealed override bool IsPublic => getMethod?.IsPublic ?? false;

    public override bool HasSet => setMethod != null;

    public override object? Get(object? thisObject)
    {
        return getMethod?.Invoke(thisObject, null);
    }

    public override void Set(object? thisObject, object? value)
    {
        if (setMethod is null)
            throw new InvalidOperationException($"The property [{Name}] of type [{DeclaringType.Name}] has no setter.");

        setMethod.Invoke(thisObject, [value]);
    }

    public override IEnumerable<T> GetCustomAttributes<T>(bool inherit)
    {
        return PropertyInfo.GetCustomAttributes<T>(inherit);
    }

    /// <summary>
    /// Returns a <see cref="string" /> that represents this instance.
    /// </summary>
    /// <returns>A <see cref="string" /> that represents this instance.</returns>
    public override string ToString()
    {
        return $"Property [{Name}] from Type [{(PropertyInfo.DeclaringType != null ? PropertyInfo.DeclaringType.FullName : string.Empty)}]";
    }
}

View on GitHub (pinned to 96fad776d2)