{"record":{"id":"096bbda23c481ea6","repo":"dotnet/wpf","slug":"sr-cannotmodifyvisualchildrenduringtreewalk","errorCode":null,"errorMessage":"SR.CannotModifyVisualChildrenDuringTreeWalk","messagePattern":"SR\\.CannotModifyVisualChildrenDuringTreeWalk","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/VisualCollection.cs","lineNumber":375,"sourceCode":"        private void ConnectChild(int index, Visual value)\n        {\n            //\n            // -- Approved By The Core Team --\n            //\n            // Do not allow foreign threads to change the tree.\n            // (This is a noop if this object is not assigned to a Dispatcher.)\n            //\n            // We also need to ensure that the tree is homogenous with respect\n            // to the dispatchers that the elements belong to.\n            //\n            _owner.VerifyAccess();\n            value.VerifyAccess();\n            \n            // It is invalid to modify the children collection that we \n            // might be iterating during a property invalidation tree walk.\n            if (_owner.IsVisualChildrenIterationInProgress)\n            {\n                throw new InvalidOperationException(SR.CannotModifyVisualChildrenDuringTreeWalk);\n            }\n\n            Debug.Assert(value != null);\n            Debug.Assert(_items[index] == null);\n            Debug.Assert(value._parent == null);\n            Debug.Assert(!value.IsRootElement);\n\n            value._parentIndex = index;\n            _items[index] = value;\n            IncrementVersion();\n\n            // Notify the Visual tree about the children changes. \n            _owner.InternalAddVisualChild(value);\n        }\n\n        /// <summary>\n        /// Disconnects a child.\n        /// </summary>","sourceCodeStart":357,"sourceCodeEnd":393,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/VisualCollection.cs#L357-L393","documentation":"Thrown by VisualCollection.ConnectChild when children are added while the owner visual is iterating its children collection during a property-invalidation tree walk (IsVisualChildrenIterationInProgress). Mutating the collection during that walk would corrupt the in-progress iteration, so WPF fails fast with InvalidOperationException.","triggerScenarios":"Calling Add or Insert (which call ConnectChild) from within a callback that runs during visual-tree property invalidation — e.g. inside OnVisualChildrenChanged during an active walk, or property-changed handlers that synchronously add children while WPF is enumerating the same collection.","commonSituations":"Custom panels adding children in response to property invalidations; code hooks (e.g. AutomationPeer, layout notifications) that mutate children re-entrantly during tree walks.","solutions":["Defer the mutation: Dispatcher.BeginInvoke(DispatcherPriority.Background, () => collection.Add(child)) so it runs after the walk completes.","Buffer pending additions in a list during the callback and apply them after (e.g. at Loaded or next layout pass).","Restructure so children are added before triggering the property change that starts the walk."],"exampleFix":"// before\nprotected override void OnRenderSizeChanged(SizeChangedInfo info)\n{\n    Children.Add(BuildChild()); // may throw during a tree walk\n}\n// after\nDispatcher.BeginInvoke(DispatcherPriority.Background,\n    new Action(() => Children.Add(BuildChild())));","handlingStrategy":"try-catch","validationCode":"if (((Visual)VisualTreeHelper.GetParent(child) ?? owner).CheckAccess()\n    && owner.IsVisualChildrenIterationInProgress /* requires internal access */) { /* defer */ }","typeGuard":null,"tryCatchPattern":"try { collection.Insert(0, child); }\ncatch (InvalidOperationException) {\n    Dispatcher.BeginInvoke(DispatcherPriority.Background,\n        new Action(() => collection.Insert(0, child)));\n}","preventionTips":["Never mutate visual children from property-changed or invalidation callbacks.","Use Dispatcher.BeginInvoke to defer Add/Insert past the tree walk.","Buffer pending additions and apply them after the current layout pass.","Keep child-list changes on the UI thread at stable points (Loaded/Unloaded)."],"tags":["wpf","visual-collection","tree-walk","reentrancy","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"}