{"record":{"id":"dfce21983a567ce1","repo":"dotnet/wpf","slug":"sr-format-sr-layoutmanager-deeprecursion-s","errorCode":null,"errorMessage":"SR.Format(SR.LayoutManager_DeepRecursion, s_LayoutRecursionLimit)","messagePattern":"SR\\.Format\\(SR\\.LayoutManager_DeepRecursion, s_LayoutRecursionLimit\\)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/LayoutManager.cs","lineNumber":132,"sourceCode":"            ((ContextLayoutManager)arg).NeedsRecalc();\n            return null;\n        }\n\n        private bool hasDirtiness\n        {\n            get\n            {\n                return (!MeasureQueue.IsEmpty) || (!ArrangeQueue.IsEmpty);\n            }\n        }\n\n        internal void EnterMeasure()\n        {\n            Dispatcher._disableProcessingCount++;\n            _lastExceptionElement = null;\n            _measuresOnStack++;\n            if(_measuresOnStack > s_LayoutRecursionLimit)\n                throw new InvalidOperationException(SR.Format(SR.LayoutManager_DeepRecursion, s_LayoutRecursionLimit));\n\n            _firePostLayoutEvents = true;\n        }\n\n        internal void ExitMeasure()\n        {\n            _measuresOnStack--;\n            Dispatcher._disableProcessingCount--;\n        }\n\n        internal void EnterArrange()\n        {\n            Dispatcher._disableProcessingCount++;\n            _lastExceptionElement = null;\n            _arrangesOnStack++;\n            if(_arrangesOnStack > s_LayoutRecursionLimit)\n                throw new InvalidOperationException(SR.Format(SR.LayoutManager_DeepRecursion, s_LayoutRecursionLimit));\n","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/LayoutManager.cs#L114-L150","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nprotected override Size MeasureOverride(Size availableSize)\n{\n    UpdateLayout(); // re-enters measure -> DeepRecursion\n    ...\n}\n// after\nprotected override Size MeasureOverride(Size availableSize)\n{\n    Dispatcher.BeginInvoke(() => child.InvalidateMeasure(), DispatcherPriority.Loaded);\n    ...\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { element.Measure(availableSize); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"recursion\") || ex.Message.Contains(\"layout\")) { Debugger.Break(); /* diagnose cycle */ }","preventionTips":["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"],"tags":["wpf","layout","recursion","invalidoperation"],"backgroundTag":"layout-recursion-limit","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"}