{"record":{"id":"bd564874f2bc8631","repo":"dotnet/wpf","slug":"sr-setonreadonlyobjectnotallowed","errorCode":null,"errorMessage":"SR.SetOnReadOnlyObjectNotAllowed","messagePattern":"SR\\.SetOnReadOnlyObjectNotAllowed","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/DependencyObject.cs","lineNumber":627,"sourceCode":"        }\n\n        /// <summary>\n        ///     The common code shared by all variants of SetValue\n        /// </summary>\n        // Takes metadata from caller because most of them have already retrieved it\n        //  for their own purposes, avoiding the duplicate GetMetadata call.\n        private void SetValueCommon(\n            DependencyProperty  dp,\n            object              value,\n            PropertyMetadata    metadata,\n            bool                coerceWithDeferredReference,\n            bool                coerceWithCurrentValue,\n            OperationType       operationType,\n            bool                isInternal)\n        {\n            if (IsSealed)\n            {\n                throw new InvalidOperationException(SR.Format(SR.SetOnReadOnlyObjectNotAllowed, this));\n            }\n\n            Expression newExpr = null;\n            DependencySource[] newSources = null;\n\n            EntryIndex entryIndex = LookupEntry(dp.GlobalIndex);\n\n            // Treat Unset as a Clear\n            if( value == DependencyProperty.UnsetValue )\n            {\n                Debug.Assert(!coerceWithCurrentValue, \"Don't call SetCurrentValue with UnsetValue\");\n                // Parameters should have already been validated, so we call\n                //  into the private method to avoid validating again.\n                ClearValueCommon(entryIndex, dp, metadata);\n                return;\n            }\n\n            // Validate the \"value\" against the DP.","sourceCodeStart":609,"sourceCodeEnd":645,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Windows/DependencyObject.cs#L609-L645","documentation":"DependencyObject.SetValueCommon — the common path for SetValue, SetCurrentValue, SetDeferredValue and friends — throws InvalidOperationException(SR.SetOnReadOnlyObjectNotAllowed, this) when IsSealed is true. A DependencyObject becomes sealed (read-only) when it is being used by the property system itself, e.g. a Style/Template or a frozen Freezable-like state; sealed objects cannot have any property values set.","triggerScenarios":"Calling SetValue/SetCurrentValue on a DependencyObject after it was sealed — e.g. mutating a Style's Setters while the style is applied, modifying a FrameworkTemplate in use, or setting values on an object returned sealed by an API.","commonSituations":"Editing styles/templates at runtime while in use; sharing one DependencyObject across controls after it was sealed; copying a sealed object by reference instead of cloning.","solutions":["Check IsSealed before mutation; if sealed, call Clone()/CloneCurrentValue() (for Freezables) or create a new instance and modify the copy.","Unapply the object (e.g. remove the Style from controls) before editing, then reapply.","Design read-only data as immutable from the start so sealing doesn't surprise callers."],"exampleFix":"// before\nif (myStyle.Setters.Count == 0)\n    myStyle.Setters.Add(new Setter(...)); // may throw if sealed\n// after\nif (myStyle.IsSealed)\n    myStyle = myStyle.Clone();\nmyStyle.Setters.Add(new Setter(...));","handlingStrategy":"type-guard","validationCode":"if (obj.IsSealed)\n    obj = ((Freezable)obj).Clone(); // or construct a new instance","typeGuard":"bool CanMutate(DependencyObject o) => o is { IsSealed: false };","tryCatchPattern":"try { style.Setters.Add(setter); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"sealed\") || ex.Message.Contains(\"read-only\"))\n{\n    style = style.Clone();\n    style.Setters.Add(setter);\n}","preventionTips":["Check IsSealed before mutating any DependencyObject, especially Styles/Templates.","Clone (Freezable.Clone) instead of mutating shared instances.","Do styling mutations before the style is applied to controls."],"tags":["wpf","dependency-object","sealed","invalid-operation"],"backgroundTag":"invalid-state-transition","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"}