dotnet/wpf · error · InvalidOperationException
SR.Format(SR.LayoutManager_DeepRecursion…
Error message
SR.Format(SR.LayoutManager_DeepRecursion, s_LayoutRecursionLimit)
What it means
The WPF LayoutManager enforces s_LayoutRecursionLimit on nested Measure calls; when _measuresOnStack exceeds that limit it throws InvalidOperationException. This guards against infinite measure recursion (an element triggering its own re-measure synchronously) which would otherwise stack-overflow.
Solutions
- Find the cycle: check for calls to UpdateLayout/Measure/InvalidateMeasure inside MeasureOverride or property-change handlers and move them out (defer with Dispatcher.BeginInvoke)
- Break reciprocal layout dependencies between parent and child so measure does not re-trigger measure on the same tree path
- Reduce visual-tree nesting depth (flatten nested ItemsControls/panels, virtualize lists)
- If depth is legitimate, refactor to an iterative layout approach — the recursion limit cannot be raised
Example fix
// before
protected override Size MeasureOverride(Size availableSize)
{
UpdateLayout(); // re-enters measure -> DeepRecursion
...
}
// after
protected override Size MeasureOverride(Size availableSize)
{
Dispatcher.BeginInvoke(() => child.InvalidateMeasure(), DispatcherPriority.Loaded);
...
} Defensive patterns
Strategy: try-catch
Try / catch
try { element.Measure(availableSize); }
catch (InvalidOperationException ex) when (ex.Message.Contains("recursion") || ex.Message.Contains("layout")) { Debugger.Break(); /* diagnose cycle */ } Prevention
- Never call UpdateLayout/Measure inside MeasureOverride or its property callbacks
- Defer InvalidateMeasure calls with Dispatcher.BeginInvoke at a lower priority
- Flatten deeply nested visual trees and avoid circular measure dependencies
When it happens
Trigger: A MeasureOverride (or layout callback on the measure path) synchronously invalidates and re-measures an ancestor/descendant in a cycle — e.g. calling UpdateLayout or Measure inside MeasureOverride, or a circular size-negotiation loop between parent and child.
Common situations: Custom panels that call InvalidateMeasure/UpdateLayout on other elements inside MeasureOverride; third-party controls with cyclical layout dependencies; data-bound size changes that fire layout synchronously; deeply recursive visual trees such as nested ItemsControls or recursion-generating templates.
Related errors
- SR.ArrangeReentrancyInvalid
- SR.MeasureReentrancyInvalid
- 0x80040206
- ArgumentNullException: child
- Microsoft.Windows.Controls.SR.Format(Microsoft.Windows.Contr…
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/dfce21983a567ce1.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/LayoutManager.cs:132
((ContextLayoutManager)arg).NeedsRecalc();
return null;
}
private bool hasDirtiness
{
get
{
return (!MeasureQueue.IsEmpty) || (!ArrangeQueue.IsEmpty);
}
}
internal void EnterMeasure()
{
Dispatcher._disableProcessingCount++;
_lastExceptionElement = null;
_measuresOnStack++;
if(_measuresOnStack > s_LayoutRecursionLimit)
throw new InvalidOperationException(SR.Format(SR.LayoutManager_DeepRecursion, s_LayoutRecursionLimit));
_firePostLayoutEvents = true;
}
internal void ExitMeasure()
{
_measuresOnStack--;
Dispatcher._disableProcessingCount--;
}
internal void EnterArrange()
{
Dispatcher._disableProcessingCount++;
_lastExceptionElement = null;
_arrangesOnStack++;
if(_arrangesOnStack > s_LayoutRecursionLimit)
throw new InvalidOperationException(SR.Format(SR.LayoutManager_DeepRecursion, s_LayoutRecursionLimit));
View on GitHub (pinned to 81131a70a4)