dotnet/wpf · error · InvalidOperationException
SR.TreeLoop
Error message
SR.TreeLoop
What it means
During event routing the number of elements processed exceeded MAX_ELEMENTS_IN_ROUTE, which the framework treats as a cyclic or runaway tree. InvalidOperationException(SR.TreeLoop) aborts the route. It protects against infinite loops caused by malformed visual/logical trees.
Solutions
- Find and fix the cycle in the visual/logical tree (inspect Parent chains of elements involved in the route)
- Avoid adding/removing or reparenting elements inside handlers while the event is routing
- Reduce hierarchy depth or split the route
- Debug with a tree dump (e.g. VisualTreeHelper.GetParent walking) before the event is raised
Example fix
// before
child.Parent = parent; parent.Children.Add(child); // possible cycle when child already ancestor
// after
if (!IsAncestorOf(child)) { parent.Children.Add(child); } Defensive patterns
Strategy: try-catch
Validate before calling
// Verify no parent cycle before raising
bool HasCycle(DependencyObject start) { var seen = new HashSet<DependencyObject>(); var cur = start;
while (cur != null) { if (!seen.Add(cur)) return true; cur = VisualTreeHelper.GetParent(cur) ?? LogicalTreeHelper.GetParent(cur) as DependencyObject; } return false; } Try / catch
try { element.RaiseEvent(args); }
catch (InvalidOperationException ex) when (ex.Message.Contains("loop") || ex.Message.Contains("TreeLoop")) { log.Error("Possible visual-tree cycle during routing", ex); } Prevention
- Never reparent elements inside routed-event handlers; defer with Dispatcher.BeginInvoke
- Assert acyclic parent chains in debug builds when building custom panels
- Keep visual tree depth reasonable and avoid accidental re-entrant RaiseEvent
When it happens
Trigger: Raising a routed event whose visual/logical tree path contains a cycle or an abnormally deep chain; reparenting elements during the route so traversal never terminates.
Common situations: Bugs in custom panels/controls that create parent-child loops (A is visual child of B and vice versa); changing the tree inside an event handler; pathological deep element hierarchies.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- ArgumentOutOfRangeException(routedEvent)
- InvalidEnumArgumentException: routingStrategy
- SR.ClassTypeIllegal
- SR.DuplicateEventName
- SR.Format(SR.ParserBamlEvent, eventIdName)
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/434467973b1f2719.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/UIElement.cs:1707
UIElement uiElement = e as UIElement;
ContentElement contentElement = null;
UIElement3D uiElement3D = null;
if (uiElement == null)
{
contentElement = e as ContentElement;
if (contentElement == null)
{
uiElement3D = e as UIElement3D;
}
}
// Protect against infinite loops by limiting the number of elements
// that we will process.
if (cElements++ > MAX_ELEMENTS_IN_ROUTE)
{
throw new InvalidOperationException(SR.TreeLoop);
}
// Allow the element to adjust source
object newSource = null;
if (uiElement != null)
{
newSource = uiElement.AdjustEventSource(args);
}
else if (contentElement != null)
{
newSource = contentElement.AdjustEventSource(args);
}
else if (uiElement3D != null)
{
newSource = uiElement3D.AdjustEventSource(args);
}
// Add changed source information to the routeView on GitHub (pinned to 81131a70a4)