dotnet/wpf · error · InvalidOperationException
SR.RowCacheCannotModifyNonExistentLayout
Error message
SR.RowCacheCannotModifyNonExistentLayout
What it means
AddPageRange adds a range of pages to the completed row layout. If the layout was never completed (_isLayoutCompleted == false), there is no layout structure to modify, so an InvalidOperationException (SR.RowCacheCannotModifyNonExistentLayout) is thrown. It is an internal guard ensuring page-add updates only apply to a fully computed layout.
Solutions
- Wait for the layout to complete before applying page-added changes (only raise page-cache changes after _isLayoutCompleted is true)
- Ensure the initial RecalcRows/layout pass runs to completion before the paginator reports page changes
- If implementing custom change handling, check IsLayoutCompleted before calling page-mutation APIs
Example fix
// before
cache.AddPage(startPage, count);
// after
if (cache.IsLayoutCompleted)
{
cache.AddPage(startPage, count);
}
else
{
cache.RecalcRows(0, columns);
} Defensive patterns
Strategy: validation
Validate before calling
if (!cache.IsLayoutCompleted) { /* wait for layout or call RecalcRows */ } Try / catch
try { cache.AddPage(startPage, count); } catch (InvalidOperationException) { pendingChanges.Enqueue((startPage, count)); } Prevention
- Queue page changes until layout completion, then flush them
- Never emit page-added notifications from a paginator before the first layout pass finishes
When it happens
Trigger: OnPageCacheChanged (or a RowCacheChange handler) routing an Add change through AddPageRange while the row layout has not finished being computed (_isLayoutCompleted is false).
Common situations: Pagination updates (page count changes) arriving while the initial row layout pass is still in progress; custom paginators issuing incremental page-added notifications before the first full layout completes; race between pagination events and layout completion.
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
- parameter
- SR.Format(SR.TextSchema_CannotSplitElement…
- SR.NoElementObject
- SR.PaginatorNegativePageNumber
- SR.TextPositionIsFrozen
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/09ffb1e40381a5e7.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/MS/Internal/documents/RowCache.cs:868
//Add this page to the row
newRow.AddPage(pageSize);
}
return newRow;
}
/// <summary>
/// Given a range of pages, adds the pages to the existing row cache,
/// adding new rows where necessary.
/// </summary>
/// <param name="startPage">The first page to add to the layout</param>
/// <param name="count">The number of pages to add.</param>
private RowCacheChange AddPageRange(int startPage, int count)
{
if (!_isLayoutCompleted)
{
throw new InvalidOperationException(SR.RowCacheCannotModifyNonExistentLayout);
}
int currentPage = startPage;
int lastPage = startPage + count;
int startRow = 0;
int rowCount = 0;
//First we check to see if startPage is such that we'd end up skipping
//pages in the document -- that is, if the last page in our layout is currently
//10 and start is 15, we need to fill in pages 11-14 as well.
if (startPage > LastPageInCache + 1)
{
currentPage = LastPageInCache + 1;
}
//Get the last row in the layout
RowInfo lastRow = _rowCache[_rowCache.Count - 1];View on GitHub (pinned to 81131a70a4)