dotnet/wpf · error · InvalidOperationException
SR.TextContainerChangingReentrancyInvalid
Error message
SR.TextContainerChangingReentrancyInvalid
What it means
FlowDocumentFormatter.Format throws InvalidOperationException(SR.TextContainerChangingReentrancyInvalid) when formatting is requested while a content change (edit) is in progress on the document's TextContainer (StructuralCache.IsContentChangeInProgress). Formatting cannot run against a TextContainer that is mid-change; WPF throws to protect container/incremental-format state.
Solutions
- Move formatting/pagination requests out of the change-notification scope; defer with Dispatcher.BeginInvoke until the change completes.
- Do not call layout/pagination APIs inside TextChanged/ContentChanged handlers on the same FlowDocument.
- Batch document edits so change scopes are short and formatting is requested afterward.
- Wrap mutations so that any re-layout is triggered once after all edits finish.
Example fix
// before
document.StructuralCache.TextContainer.Changed += (s, e) => {
formatter.Format(0); // throws: change in progress
};
// after
document.StructuralCache.TextContainer.Changed += (s, e) => {
Dispatcher.BeginInvoke(new Action(() => formatter.Format(0)),
System.Windows.Threading.DispatcherPriority.Background);
}; Defensive patterns
Strategy: validation
Validate before calling
if (_document.StructuralCache.IsContentChangeInProgress)
return; // defer formatting until the edit completes Type guard
bool CanFormat(FlowDocument doc) => !doc.StructuralCache.IsContentChangeInProgress && !doc.StructuralCache.IsFormattingInProgress;
Try / catch
try { formatter.Format(offset); }
catch (InvalidOperationException ex) {
Dispatcher.BeginInvoke(new Action(() => formatter.Format(offset)), DispatcherPriority.Background);
} Prevention
- Do not trigger layout/pagination inside ContentChanged/TextChanged handlers
- Complete edit transactions before requesting formatting
- Use a dirty flag and format on the next dispatcher pass
- Avoid reentrant document mutations from event handlers
When it happens
Trigger: Calling FlowDocumentFormatter.Format (directly or through layout/pagination APIs) from inside a TextContainer change scope — e.g. inside a TextContainer.Change event handler, inside TextPointer insert/remove operations, or from code executed during a document mutation.
Common situations: Text-changed event handlers that force layout or paginate synchronously; document edits performed inside layout/pagination notifications; RichTextBox/TextBox event handlers that trigger printing or pagination of the same FlowDocument.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- SR.FlowDocumentFormattingReentrancy
- SR.FlowDocumentFormattingReentrancy
- SR.FlowDocumentInvalidContnetChange
- SR.TextContainerChangingReentrancyInvalid
- SR.TextContainerChangingReentrancyInvalid
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/fe16c56079d297be.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/FlowDocumentFormatter.cs:63
#region Internal Methods
/// <summary>
/// Formatts content.
/// </summary>
/// <param name="constraint">Constraint size.</param>
internal void Format(Size constraint)
{
Thickness pageMargin;
Size pageSize;
// Reentrancy check.
if (_document.StructuralCache.IsFormattingInProgress)
{
throw new InvalidOperationException(SR.FlowDocumentFormattingReentrancy);
}
if (_document.StructuralCache.IsContentChangeInProgress)
{
throw new InvalidOperationException(SR.TextContainerChangingReentrancyInvalid);
}
// Check if we can continue with formatting without nuking incremental udpate info.
if (_document.StructuralCache.IsFormattedOnce)
{
if (!_lastFormatSuccessful)
{
// We cannot resolve update info if last formatting was unsuccessful.
_document.StructuralCache.InvalidateFormatCache(true);
}
if (!_arrangedAfterFormat && (!_document.StructuralCache.ForceReformat || !_document.StructuralCache.DestroyStructure))
{
// Need to clear update info by running arrange process.
// This is necessary, because Format may be called more than once
// before Arrange is called. But PTS is not able to merge update info.
// To protect against loosing incremental changes delta, need
// to arrange the page and create all necessary visuals.
_documentPage.Arrange(_documentPage.ContentSize);View on GitHub (pinned to 81131a70a4)