Unity-Technologies/UnityCsReference · error · InvalidOperationException
Number of rows does not match number of row rects. Did you…
Error message
Number of rows does not match number of row rects. Did you remember to update the row rects when BuildRootAndRows was called? Number of rows: {0}, number of custom row rects: {1}. Falling back to fixed row height. What it means
Thrown during visible-row computation (in TreeViewControlGUI) when the number of rows (rowCount) does not match the number of custom row rects (m_RowRects.Count). This means BuildRows changed the row count but RefreshRowRects was not called to recompute the per-row Rect array, leaving the geometry inconsistent. The message says it 'falls back' but the code actually nulls m_RowRects and throws.
Solutions
- Call treeView.Reload() then treeView.RefreshCustomRowHeights() whenever the underlying data changes.
- Ensure BuildRows and GetCustomRowHeight are consistent in the row count they assume.
- Override BuildRows to call RefreshCustomRowHeights internally if rows change, or ensure m_RowRects is rebuilt in BuildRows.
Example fix
// before // data changed, rows differ from rects OnDataChanged(); // after OnDataChanged(); treeView.Reload(); treeView.RefreshCustomRowHeights(); // recomputes m_RowRects to match rows
Defensive patterns
Strategy: validation
Validate before calling
treeView.Reload(); treeView.RefreshCustomRowHeights(); // keeps m_RowRects in sync with row count
Prevention
- Call Reload + RefreshCustomRowHeights after any data change.
- Keep BuildRows and GetCustomRowHeight consistent in row count.
- Recompute custom row rects whenever rows are added or removed.
When it happens
Trigger: Overriding GetCustomRowHeight and changing row data (Reload/BuildRows) without calling RefreshCustomRowHeights afterward; BuildRows returning a different count than when rects were last computed; rows added/removed between reload and render.
Common situations: Dynamic TreeView where items are added/removed at runtime without calling Reload + RefreshCustomRowHeights; custom BuildRows that filters rows differently each call.
Related errors
- Input row index: is invalid. Number of rows rects: …
- Only call RefreshCustomRowHeights if you have overridden…
- FindItem failed: root item has not been created yet
- GetCellRect can only be called when 'multiColumnHeader' has…
- BuildRoot should set a valid root item.
AI-assisted analysis of Unity-Technologies/UnityCsReference@225b0fbdb5 (2026-08-13).
Data as JSON: /api/errors/7e67972efaa08ee6.
Report an issue: GitHub.
Appendix: source
Thrown at Editor/Mono/GUI/TreeView/TreeViewControl/TreeViewControlGUI.cs:275
{
base.GetFirstAndLastRowVisible(out firstRowVisible, out lastRowVisible);
return;
}
var rowCount = m_TreeView.data.rowCount;
if (rowCount == 0 || Mathf.Approximately(m_TreeView.visibleRect.height, 0.0f))
{
firstRowVisible = lastRowVisible = -1;
return;
}
if (rowCount != m_RowRects.Count)
{
var errorMessage = string.Format(
"Number of rows does not match number of row rects. Did you remember to update the row rects when BuildRootAndRows was called? Number of rows: {0}, number of custom row rects: {1}. Falling back to fixed row height.",
rowCount, m_RowRects.Count);
m_RowRects = null;
throw new InvalidOperationException(errorMessage);
}
float topPixel = m_TreeView.state.scrollPos.y;
float heightInPixels = m_TreeView.visibleRect.height;
int firstVisible = -1;
int lastVisible = -1;
for (int i = 0; i < m_RowRects.Count; ++i)
{
bool visible = ((m_RowRects[i].y > topPixel && (m_RowRects[i].y < topPixel + heightInPixels))) ||
((m_RowRects[i].yMax > topPixel && (m_RowRects[i].yMax < topPixel + heightInPixels)));
if (visible)
{
if (firstVisible == -1)
firstVisible = i;
lastVisible = i;
}View on GitHub (pinned to 225b0fbdb5)