{"record":{"id":"e811946a5f8b191f","repo":"dotnet/aspnetcore","slug":"the-type-targettype-fullname-declares-a-proper","errorCode":null,"errorMessage":"The type '{targetType.FullName}' declares a property matching the name '{propertyName}' that is not public. Persistent service properties must be public.","messagePattern":"The type '(.+?)' declares a property matching the name '(.+?)' that is not public\\. Persistent service properties must be public\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Components/Components/src/PersistentState/PersistentServicesRegistry.cs","lineNumber":191,"sourceCode":"                foreach (var attribute in propertyInfo.GetCustomAttributes())\n                {\n                    if (attribute is PersistentStateAttribute persistentStateAttribute)\n                    {\n                        parameterAttribute = persistentStateAttribute;\n                        break;\n                    }\n                }\n                if (parameterAttribute == null)\n                {\n                    continue;\n                }\n\n                var propertyName = propertyInfo.Name;\n                var key = ComputeKey(keyType, propertyName);\n                keys.Add(new(key, propertyInfo.PropertyType));\n                if (propertyInfo.SetMethod == null || !propertyInfo.SetMethod.IsPublic)\n                {\n                    throw new InvalidOperationException(\n                        $\"The type '{targetType.FullName}' declares a property matching the name '{propertyName}' that is not public. Persistent service properties must be public.\");\n                }\n\n                if (propertyInfo.GetMethod == null || !propertyInfo.GetMethod.IsPublic)\n                {\n                    throw new InvalidOperationException(\n                        $\"The type '{targetType.FullName}' declares a property matching the name '{propertyName}' that is not public. Persistent service properties must be public.\");\n                }\n\n                var restoreOptions = new RestoreOptions\n                {\n                    RestoreBehavior = parameterAttribute.RestoreBehavior,\n                    AllowUpdates = parameterAttribute.AllowUpdates,\n                };\n\n                var propertySetter = new PropertySetter(targetType, propertyInfo);\n                var propertyGetter = new PropertyGetter(targetType, propertyInfo);\n","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/Components/Components/src/PersistentState/PersistentServicesRegistry.cs#L173-L209","documentation":"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.","triggerScenarios":"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>.","commonSituations":"Using init-only or get-only properties ({ get; init; } / { get; }); { get; private set; } for encapsulation; record primary constructors producing non-public setters.","solutions":["Make the setter public: { get; set; }.","If the property must not be publicly settable, remove [PersistentState] since the framework cannot restore into it.","For records, declare the property with a public set accessor.","Run a quick reflection audit over registered service types to catch non-public setters before runtime."],"exampleFix":"// before\n[PersistentState]\npublic Cart Cart { get; private set; }\n\n// after\n[PersistentState]\npublic Cart Cart { get; set; }","handlingStrategy":"validation","validationCode":"// Reflection audit: ensure every [PersistentState] property on a persistent service\n// has a public setter before the app starts.\nstatic void ValidatePersistentServices(params Type[] types)\n{\n    foreach (var t in types)\n    foreach (var p in t.GetProperties())\n    {\n        if (p.GetCustomAttribute<PersistentStateAttribute>() is null) continue;\n        if (p.GetSetMethod(nonPublic: false) is null)\n            throw new InvalidOperationException(\n                $\"{t.FullName}.{p.Name} has [PersistentState] but no public setter.\");\n    }\n}","typeGuard":"static bool HasPublicSetter(PropertyInfo p) => p.GetSetMethod(nonPublic: false) is not null;","tryCatchPattern":null,"preventionTips":["Use { get; set; } for every [PersistentState] property on a persistent service.","Avoid { get; private set; }, { get; init; }, and get-only properties for persisted service state.","Run a startup reflection audit over registered persistent service types.","For records, declare persisted properties with explicit public setters."],"tags":["blazor","component-state","persistence","reflection","services","visibility"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}