{"record":{"id":"446d31866c437c87","repo":"dotnet/wpf","slug":"sr-flowdocumentformattingreentrancy","errorCode":null,"errorMessage":"SR.FlowDocumentFormattingReentrancy","messagePattern":"SR\\.FlowDocumentFormattingReentrancy","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/FlowDocumentFormatter.cs","lineNumber":59,"sourceCode":"        //  Internal Methods\n        //\n        //-------------------------------------------------------------------\n\n        #region Internal Methods\n\n        /// <summary>\n        /// Formatts content.\n        /// </summary>\n        /// <param name=\"constraint\">Constraint size.</param>\n        internal void Format(Size constraint)\n        {\n            Thickness pageMargin;\n            Size pageSize;\n\n            // Reentrancy check.\n            if (_document.StructuralCache.IsFormattingInProgress)\n            {\n                throw new InvalidOperationException(SR.FlowDocumentFormattingReentrancy);\n            }\n            if (_document.StructuralCache.IsContentChangeInProgress)\n            {\n                throw new InvalidOperationException(SR.TextContainerChangingReentrancyInvalid);\n            }\n\n            // Check if we can continue with formatting without nuking incremental udpate info.\n            if (_document.StructuralCache.IsFormattedOnce)\n            {\n                if (!_lastFormatSuccessful)\n                {\n                    // We cannot resolve update info if last formatting was unsuccessful.\n                    _document.StructuralCache.InvalidateFormatCache(true);\n                }\n                if (!_arrangedAfterFormat && (!_document.StructuralCache.ForceReformat || !_document.StructuralCache.DestroyStructure))\n                {\n                    // Need to clear update info by running arrange process.\n                    // This is necessary, because Format may be called more than once","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/FlowDocumentFormatter.cs#L41-L77","documentation":"FlowDocumentFormatter.Format throws InvalidOperationException(SR.FlowDocumentFormattingReentrancy) when formatting is requested while another formatting pass is already in progress on the same FlowDocument (StructuralCache.IsFormattingInProgress is true). WPF's FlowDocument formatting state is not reentrant; nested calls would corrupt incremental layout state. The library fails fast instead of queueing the work.","triggerScenarios":"Calling FlowDocumentFormatter.Format (directly or via layout/pagination) from inside code that runs while formatting is in progress — e.g. inside a GetPage/GetPageAsync callback, a DocumentPaginator event handler, or a property-changed handler that synchronously re-triggers Format.","commonSituations":"Custom DocumentPaginator subclasses that call back into document APIs during OnGetPage; event handlers that modify layout-triggering properties while pagination is running; synchronously forcing layout from within a Print/print-chain callback.","solutions":["Ensure the code path that re-triggers formatting is not invoked during an active formatting pass; defer it (Dispatcher.BeginInvoke) instead of calling synchronously.","Never call Format/GetPage/GetPageAsync from within pagination callbacks; capture the request and process it after the current operation completes.","If custom code mutates the document, batch changes and let layout complete before requesting new pages.","Use the same DocumentPaginator instance rather than starting a second formatting pipeline concurrently."],"exampleFix":"// before\nvoid OnPaginationCompleted(object sender, EventArgs e) {\n    paginator.GetPageAsync(0, null); // may still be inside formatting\n}\n// after\nvoid OnPaginationCompleted(object sender, EventArgs e) {\n    Dispatcher.BeginInvoke(new Action(() => paginator.GetPageAsync(0, null)),\n        System.Windows.Threading.DispatcherPriority.Background);\n}","handlingStrategy":"validation","validationCode":"if (_document.StructuralCache.IsFormattingInProgress)\n    return; // or defer; do not call Format now","typeGuard":"bool CanFormat(FlowDocument doc) => !doc.StructuralCache.IsFormattingInProgress && !doc.StructuralCache.IsContentChangeInProgress;","tryCatchPattern":"try { formatter.Format(offset); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"reentrancy\") || ex.Message.Contains(\"formatting\")) {\n    Dispatcher.BeginInvoke(new Action(() => formatter.Format(offset)), DispatcherPriority.Background);\n}","preventionTips":["Never call formatting/pagination APIs from within pagination callbacks","Defer re-layout requests with Dispatcher.BeginInvoke","Keep one formatting pipeline per FlowDocument","Batch document mutations outside layout passes"],"tags":["wpf","flowdocument","reentrancy","pagination"],"backgroundTag":"unsupported-operation","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"}