dotnet/wpf · error · InvalidOperationException
SR.TextContainerChangingReentrancyInvalid
Error message
SR.TextContainerChangingReentrancyInvalid
What it means
FlowDocumentPaginator.GetPageAsync throws InvalidOperationException(SR.TextContainerChangingReentrancyInvalid) when called while a content change is in progress on the document's TextContainer (StructuralCache.IsContentChangeInProgress). Formatting cannot start against a mutating TextContainer; WPF throws rather than produce inconsistent pages.
Solutions
- Defer GetPageAsync until the content change completes — post it with Dispatcher.BeginInvoke from change handlers.
- Never request pagination from within ContentChanged/TextChanged handlers on the same document.
- Complete all document edits before initiating printing/pagination.
- If you must react to edits, mark a dirty flag and paginate on a subsequent dispatcher pass.
Example fix
// before
richTextBox.TextChanged += (s, e) => {
paginator.GetPageAsync(0, null); // content change in progress
};
// after
richTextBox.TextChanged += (s, e) => {
Dispatcher.BeginInvoke(new Action(() => paginator.GetPageAsync(0, null)),
System.Windows.Threading.DispatcherPriority.Background);
}; Defensive patterns
Strategy: validation
Validate before calling
if (!document.StructuralCache.IsContentChangeInProgress &&
!document.StructuralCache.IsFormattingInProgress)
paginator.GetPageAsync(pageNumber, userState); Type guard
bool CanPaginate(FlowDocument doc) => !doc.StructuralCache.IsContentChangeInProgress && !doc.StructuralCache.IsFormattingInProgress;
Try / catch
try { paginator.GetPageAsync(n, state); }
catch (InvalidOperationException) {
Dispatcher.BeginInvoke(new Action(() => paginator.GetPageAsync(n, state)), DispatcherPriority.Background);
} Prevention
- Do not paginate from TextChanged/ContentChanged handlers
- Finish document edits before initiating printing/pagination
- Mark dirty and paginate on the next idle dispatcher pass
- Keep edit transactions short and non-nested
When it happens
Trigger: Calling GetPageAsync while the FlowDocument is inside a TextContainer change scope — e.g. from a TextChanged/ContentChanged event handler, from code executed during paragraph/text insertion, or from a nested API call that mutates the document while pagination is requested on the same call stack.
Common situations: Handlers that update document text and immediately request pages; RichTextBox automation that edits content and paginates in the same event; printing triggered from within a text-editing transaction.
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.TextContainerChangingReentrancyInvalid
- SR.TextContainerChangingReentrancyInvalid
- args
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/d1e58408fecd6335.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/FlowDocumentPaginator.cs:83
/// <exception cref="ArgumentOutOfRangeException">
/// Throws ArgumentOutOfRangeException if PageNumber is negative.
/// </exception>
public override void GetPageAsync(int pageNumber, object userState)
{
// Page number cannot be negative.
if (pageNumber < 0)
{
throw new ArgumentOutOfRangeException(nameof(pageNumber), SR.IDPNegativePageNumber);
}
// Reentrancy check.
if (_document.StructuralCache.IsFormattingInProgress)
{
throw new InvalidOperationException(SR.FlowDocumentFormattingReentrancy);
}
if (_document.StructuralCache.IsContentChangeInProgress)
{
throw new InvalidOperationException(SR.TextContainerChangingReentrancyInvalid);
}
DocumentPage page = null;
if (!_backgroundPagination)
{
page = GetPage(pageNumber);
}
else
{
// If entire content has been already pre-paginated (BreakRecordTable is clean)
// and requesting non-existing page number, return DocumentPage.Missing.
if (_brt.IsClean && !_brt.HasPageBreakRecord(pageNumber))
{
page = DocumentPage.Missing;
}
if (_brt.HasPageBreakRecord(pageNumber))View on GitHub (pinned to 81131a70a4)