dotnet/aspnetcore · error · InvalidOperationException

The type '{targetType.FullName}' declares a property matchin

Error message

The type '{targetType.FullName}' declares a property matching the name '{propertyName}' that is not public. Persistent service properties must be public.

What it means

Thrown by PersistentServicesRegistry.PropertiesAccessor when a property decorated with [PersistentStateAttribute] has a setter that is null or non-public. Persistent service properties must expose a public setter so the framework can write restored values back via PropertySetter during restore.

Source

Thrown at src/Components/Components/src/PersistentState/PersistentServicesRegistry.cs:191

                foreach (var attribute in propertyInfo.GetCustomAttributes())
                {
                    if (attribute is PersistentStateAttribute persistentStateAttribute)
                    {
                        parameterAttribute = persistentStateAttribute;
                        break;
                    }
                }
                if (parameterAttribute == null)
                {
                    continue;
                }

                var propertyName = propertyInfo.Name;
                var key = ComputeKey(keyType, propertyName);
                keys.Add(new(key, propertyInfo.PropertyType));
                if (propertyInfo.SetMethod == null || !propertyInfo.SetMethod.IsPublic)
                {
                    throw new InvalidOperationException(
                        $"The type '{targetType.FullName}' declares a property matching the name '{propertyName}' that is not public. Persistent service properties must be public.");
                }

                if (propertyInfo.GetMethod == null || !propertyInfo.GetMethod.IsPublic)
                {
                    throw new InvalidOperationException(
                        $"The type '{targetType.FullName}' declares a property matching the name '{propertyName}' that is not public. Persistent service properties must be public.");
                }

                var restoreOptions = new RestoreOptions
                {
                    RestoreBehavior = parameterAttribute.RestoreBehavior,
                    AllowUpdates = parameterAttribute.AllowUpdates,
                };

                var propertySetter = new PropertySetter(targetType, propertyInfo);
                var propertyGetter = new PropertyGetter(targetType, propertyInfo);

View on GitHub (pinned to 294cab2f9b)

Solutions

  1. Make the setter public: { get; set; }.
  2. If the property must not be publicly settable, remove [PersistentState] since the framework cannot restore into it.
  3. For records, declare the property with a public set accessor.
  4. Run a quick reflection audit over registered service types to catch non-public setters before runtime.

Example fix

// before
[PersistentState]
public Cart Cart { get; private set; }

// after
[PersistentState]
public Cart Cart { get; set; }
Defensive patterns

Strategy: validation

Validate before calling

// Reflection audit: ensure every [PersistentState] property on a persistent service
// has a public setter before the app starts.
static void ValidatePersistentServices(params Type[] types)
{
    foreach (var t in types)
    foreach (var p in t.GetProperties())
    {
        if (p.GetCustomAttribute<PersistentStateAttribute>() is null) continue;
        if (p.GetSetMethod(nonPublic: false) is null)
            throw new InvalidOperationException(
                $"{t.FullName}.{p.Name} has [PersistentState] but no public setter.");
    }
}

Type guard

static bool HasPublicSetter(PropertyInfo p) => p.GetSetMethod(nonPublic: false) is not null;

Prevention

When it happens

Trigger: Declaring [PersistentState] on a read-only property (no setter) or a property with a private/protected/internal setter on a service registered via AddPersistentService<T>.

Common situations: Using init-only or get-only properties ({ get; init; } / { get; }); { get; private set; } for encapsulation; record primary constructors producing non-public setters.

Related errors


AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06). Data as JSON: /api/errors/e811946a5f8b191f. Report an issue: GitHub.