dotnet/wpf · error · InvalidOperationException

SR.Format(SR.LayoutManager_DeepRecursion, TreeLevelLimit)

Error message

SR.Format(SR.LayoutManager_DeepRecursion, TreeLevelLimit)

What it means

Visual.TreeLevel limits the visual tree depth to TreeLevelLimit (about 2047 levels, stored in flag bits). Setting it beyond the limit throws InvalidOperationException(LayoutManager_DeepRecursion), preventing stack overflow during recursive layout/visual-tree traversal.

Solutions

  1. Flatten or restructure the visual tree to reduce depth
  2. Detect and break cycles in data/templates driving recursive nesting
  3. Use non-visual data structures (e.g. virtualization/ItemsControl) instead of deep visual nesting

Example fix

// before
Visual current = root;
for (int i = 0; i < 5000; i++) { var v = new Border(); current.AddVisualChild(v); current = v; }
// after
var items = new ItemsControl { ItemsSource = Enumerable.Range(0, 5000) }; // flat, virtualized
Defensive patterns

Strategy: validation

Validate before calling

int Depth(Visual v) { int d = 0; for (DependencyObject p = v; p != null; p = VisualTreeHelper.GetParent(p)) d++; return d; } // ensure < ~2047

Type guard

bool DepthWithinLimit(Visual v) => Depth(v) < 2000;

Try / catch

try { /* build tree */ } catch (InvalidOperationException ex) when (ex.Message.Contains("recursion") || ex.Message.Contains("deep")) { /* flatten tree */ }

Prevention

When it happens

Trigger: Building or embedding a visual tree deeper than TreeLevelLimit; programmatically adding nested visuals in an unbounded recursive structure.

Common situations: Recursive data-bound templates with cyclic or self-referencing data; pathological nested layouts generated from recursive algorithms.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/4d809fbb53a3df17. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Visual.cs:2733

        }

        //This is used by LayoutManager as a perf optimization for layout updates.
        //During layout updates, LM needs to find which areas of the visual tree
        //are higher in the tree - they have to be processed first to avoid multiple
        //updates of lower descendants. The tree level counter is maintained by
        //UIElement.PropagateResume/SuspendLayout methods and uses 8 bits in VisualFlags to
        //keep the count.
        internal uint TreeLevel
        {
            get
            {
                return ((uint)_flags & 0xFFE00000) >> 21;
            }
            set
            {
                if(value > TreeLevelLimit)
                {
                    throw new InvalidOperationException(SR.Format(SR.LayoutManager_DeepRecursion, TreeLevelLimit));
                }

                _flags = (VisualFlags)(((uint)_flags & 0x001FFFFF) | (value << 21));
            }
        }


        #endregion VisualChildren


        #region VisualParent

        /// <summary>
        /// Returns the parent of this Visual.  Parent may be either a Visual or Visual3D.
        /// </summary>
        protected DependencyObject VisualParent
        {
            get

View on GitHub (pinned to 81131a70a4)