{"record":{"id":"91cfaccdc619de4a","repo":"dotnet/wpf","slug":"sr-cannotwritetoreadonly","errorCode":null,"errorMessage":"SR.CannotWriteToReadOnly","messagePattern":"SR\\.CannotWriteToReadOnly","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/PropertyPathWorker.cs","lineNumber":1581,"sourceCode":"\n                    if (pd == null)\n                        dpa = info as DynamicPropertyAccessor;\n                }\n            }\n        }\n\n        private void CheckReadOnly(object item, object info)\n        {\n            PropertyInfo pi;\n            PropertyDescriptor pd;\n            DependencyProperty dp;\n            DynamicPropertyAccessor dpa;\n            SetPropertyInfo(info, out pi, out pd, out dp, out dpa);\n\n            if (pi != null)\n            {\n                if (IsPropertyReadOnly(item, pi))\n                    throw new InvalidOperationException(SR.Format(SR.CannotWriteToReadOnly, item.GetType(), pi.Name));\n            }\n            else if (pd != null)\n            {\n                if (pd.IsReadOnly)\n                    throw new InvalidOperationException(SR.Format(SR.CannotWriteToReadOnly, item.GetType(), pd.Name));\n            }\n            else if (dp != null)\n            {\n                if (dp.ReadOnly)\n                    throw new InvalidOperationException(SR.Format(SR.CannotWriteToReadOnly, item.GetType(), dp.Name));\n            }\n            else if (dpa != null)\n            {\n                if (dpa.IsReadOnly)\n                    throw new InvalidOperationException(SR.Format(SR.CannotWriteToReadOnly, item.GetType(), dpa.PropertyName));\n            }\n        }\n","sourceCodeStart":1563,"sourceCodeEnd":1599,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/Data/PropertyPathWorker.cs#L1563-L1599","documentation":"While preparing to write through a binding path, PropertyPathWorker checks whether the resolved CLR property (PropertyInfo) is read-only and throws InvalidOperationException (SR.CannotWriteToReadOnly) if so. The library refuses writes to properties that have no setter.","triggerScenarios":"A TwoWay or OneWayToSource binding (or direct SetValue on the path) targeting a get-only property, e.g. new Binding(\"FullName\") { Mode = TwoWay } where FullName has only a getter.","commonSituations":"Binding to computed/read-only model properties, forgetting Mode=OneWay, calling ItemContainerStyle setters against read-only properties, changes after a property lost its setter in a refactor.","solutions":["Add a setter to the target property, or back it with a writable field and raise PropertyChanged","Set the binding Mode to OneWay (default for most) so no write is attempted","Bind to a different writable property"],"exampleFix":"// before\npublic string FullName => $\"{First} {Last}\";\n// after\npublic string FullName\n{\n    get => $\"{First} {Last}\";\n    set { /* parse or store */ OnPropertyChanged(); }\n}","handlingStrategy":"validation","validationCode":"bool canWrite = item.GetType().GetProperty(propName)?.CanWrite == true;\nif (!canWrite) throw new InvalidOperationException($\"{propName} has no setter; use OneWay binding\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check PropertyInfo.CanWrite before choosing TwoWay/OneWayToSource","Prefer OneWay bindings for computed properties","Add setters when a property is part of an editable model contract"],"tags":["wpf","data-binding","read-only","property"],"backgroundTag":"permission-denied","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}