{"record":{"id":"8f7c36e58cedcde8","repo":"AvaloniaUI/Avalonia","slug":"property-name-doesn-t-have-a-setter","errorCode":null,"errorMessage":"Property {Name} doesn't have a setter","messagePattern":"Property (.+?) doesn't have a setter","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"src/Avalonia.Base/Data/Core/ClrPropertyInfo.cs","lineNumber":32,"sourceCode":"            _setter = setter;\n            PropertyType = propertyType;\n            Name = name;\n        }\n\n        public string Name { get; }\n        public Type PropertyType { get; }\n\n        public object? Get(object target)\n        {\n            if (_getter == null)\n                throw new NotSupportedException(\"Property \" + Name + \" doesn't have a getter\");\n            return _getter(target);\n        }\n\n        public void Set(object target, object? value)\n        {\n            if (_setter == null)\n                throw new NotSupportedException(\"Property \" + Name + \" doesn't have a setter\");\n            _setter(target, value);\n        }\n\n        public bool CanSet => _setter != null;\n        public bool CanGet => _getter != null;\n    }\n\n    public class ReflectionClrPropertyInfo : ClrPropertyInfo\n    {\n        private static Action<object, object?>? CreateSetter(PropertyInfo info)\n            => info.SetMethod is { } setMethod ?\n                (target, value) => setMethod.Invoke(target, [value]) :\n                null;\n\n        private static Func<object, object?>? CreateGetter(PropertyInfo info)\n            => info.GetMethod is { } getMethod ?\n                target => getMethod.Invoke(target, []) :\n                null;","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/AvaloniaUI/Avalonia/blob/11c542726898ae954a1ef668c65ec79ec92ab17d/src/Avalonia.Base/Data/Core/ClrPropertyInfo.cs#L14-L50","documentation":"ClrPropertyInfo.Set() throws NotSupportedException when the property has no setter (_setter is null), i.e. it is read-only (get accessor only or computed). A TwoWay or OneWayToSource binding tries to push a value back and calls Set(), which fails.","triggerScenarios":"A TwoWay or OneWayToSource binding whose target path ends on a read-only CLR property, so the engine attempts Set() and there is no setter to invoke.","commonSituations":"Binding TextBox.Text TwoWay to a computed/readonly viewmodel property; binding to a get-only property while mode resolves to TwoWay (TextBox.Text default); targeting an immutable record property.","solutions":["Change the binding Mode to OneWay or OneTime so no write-back occurs.","Make the source property mutable by adding a setter (and raising change notifications).","Bind to a different settable property on the source."],"exampleFix":"// before\npublic int Total { get; } = Compute();\n<TextBox Text=\"{Binding Total}\" />  <!-- defaults to TwoWay on TextBox.Text -->\n// after\n<TextBox Text=\"{Binding Total, Mode=OneWay}\" />","handlingStrategy":"type-guard","validationCode":"// Check CanSet before writing via ClrPropertyInfo, and verify mode is one-way if read-only.\nif (propertyInfo is ClrPropertyInfo clr && !clr.CanSet && mode != BindingMode.OneWay && mode != BindingMode.OneTime)\n    throw new InvalidOperationException($\"{clr.Name} is read-only; use OneWay/OneTime.\");","typeGuard":"static bool IsWritable(ClrPropertyInfo p) => p.CanSet;","tryCatchPattern":"try { propertyInfo.Set(target, value); }\ncatch (NotSupportedException) { /* read-only: ignore or log */ }","preventionTips":["Make bound source properties mutable (get; set;) with INotifyPropertyChanged.","Remember TextBox.Text defaults to TwoWay.","Use OneWay on computed/get-only properties."],"tags":["data-binding","reflection","clr-property","write-only"],"backgroundTag":null,"analyzedSha":"11c542726898ae954a1ef668c65ec79ec92ab17d","analyzedAt":"2026-08-13T11:57:40.261Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}