dotnet/wpf · error · InvalidOperationException
SR.ArrangeReentrancyInvalid
Error message
SR.ArrangeReentrancyInvalid
What it means
TextBlock throws this InvalidOperationException when a public or text-view method is re-entered while the Arrange (layout) pass is in progress. Arrangement positions the measured lines; reentrant calls could observe or mutate half-arranged state, so VerifyReentrancy() rejects them.
Solutions
- Defer the offending call with Dispatcher.BeginInvoke(DispatcherPriority.Background) so it runs after arrange completes.
- In SizeChanged/LayoutUpdated handlers, do not write Text/Inlines directly; guard with a re-entrancy flag of your own and schedule the update.
- For derived controls, keep ArrangeOverride read-only on the TextBlock's content and perform mutations from user-input or data-change handlers instead.
- If the query is from automation, return cached metrics and refresh on a later dispatcher priority rather than re-entering immediately.
Example fix
// before: rewriting text on SizeChanged
void OnTextBlockSizeChanged(object s, SizeChangedEventArgs e)
{
textBlock.Text = TrimToFit(textBlock.Text); // throws ArrangeReentrancyInvalid during arrange
}
// after: defer until layout is idle
void OnTextBlockSizeChanged(object s, SizeChangedEventArgs e)
{
Dispatcher.BeginInvoke(DispatcherPriority.Background,
new Action(() => textBlock.Text = TrimToFit(textBlock.Text)));
} Defensive patterns
Strategy: try-catch
Validate before calling
bool insideArrange = !textBlock.IsArrangeValid; // if false, an arrange pass is likely running if (insideArrange) Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(ApplyChange));
Type guard
static bool ArrangeSafe(TextBlock tb) => tb.IsArrangeValid;
Try / catch
try
{
UpdateTextBlock();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("arrange"))
{
Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(UpdateTextBlock));
} Prevention
- Keep SizeChanged/LayoutUpdated handlers free of Text/Inline writes.
- Use your own bool re-entrancy flag around text updates.
- Apply content changes in response to user input or data events, not layout callbacks.
- Defer with DispatcherPriority.Background to guarantee arrange has finished.
When it happens
Trigger: Calling public TextBlock members (text mutation via Text/Inlines, TextRange operations, textview queries like GetLineText) from ArrangeOverride, from a Arrange-time callback, or from code triggered synchronously during the arrange pass (e.g. SizeChanged/Render handlers that feed back into the TextBlock).
Common situations: SizeChanged or LayoutUpdated handlers that change Text or Inlines, causing another layout; custom panels arranging a TextBlock and also mutating its content; UIA clients resolving range/line APIs during arrange.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- SR.MeasureReentrancyInvalid
- SR.ArrangeReentrancyInvalid
- SR.FlowDocumentInvalidContnetChange
- SR.Format(SR.LayoutManager_DeepRecursion…
- SR.IllegalTreeChangeDetected
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/21492b4507967384.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/TextBlock.cs:3564
// ------------------------------------------------------------------
private bool CheckFlags(Flags flags)
{
return ((_flags & flags) == flags);
}
// ------------------------------------------------------------------
// Ensures none of our public (or textview) methods can be called during measure/arrange/content change.
// ------------------------------------------------------------------
private void VerifyReentrancy()
{
if(CheckFlags(Flags.MeasureInProgress))
{
throw new InvalidOperationException(SR.MeasureReentrancyInvalid);
}
if(CheckFlags(Flags.ArrangeInProgress))
{
throw new InvalidOperationException(SR.ArrangeReentrancyInvalid);
}
if(CheckFlags(Flags.ContentChangeInProgress))
{
throw new InvalidOperationException(SR.TextContainerChangingReentrancyInvalid);
}
}
/// <summary>
/// Returns index of the line that starts at the given dcp. Returns -1 if
/// no line or the line metrics collection starts at the given dcp
/// </summary>
/// <param name="dcpLine">
/// Start dcp of required line
/// </param>
private int GetLineIndexFromDcp(int dcpLine)
{
Invariant.Assert(dcpLine >= 0);View on GitHub (pinned to 81131a70a4)