facebook/lexical · error
Row before insertion index does not exist.
Error message
Row before insertion index does not exist.
What it means
In $insertTableRow, after the range check passes, the anchor row (tableRows[targetIndex]) must still be a TableRowNode. If it isn't (e.g. the table has malformed children or an empty/mismatched child list), the else branch throws 'Row before insertion index does not exist.'
Source
Thrown at packages/lexical-table/src/LexicalTableUtils.ts:246
) {
headerState |= TableCellHeaderStates.COLUMN;
}
const tableCellNode = $createTableCellNode(headerState, 1, width);
tableCellNode.append($createParagraphNode());
newTableRowNode.append(tableCellNode);
}
if (shouldInsertAfter) {
targetRowNode.insertAfter(newTableRowNode);
} else {
targetRowNode.insertBefore(newTableRowNode);
}
}
} else {
throw new Error('Row before insertion index does not exist.');
}
return tableNode;
}
const getHeaderState = (
currentState: TableCellHeaderState,
possibleState: TableCellHeaderState,
): TableCellHeaderState => {
if (
currentState === TableCellHeaderStates.BOTH ||
currentState === possibleState
) {
return possibleState;
}
return TableCellHeaderStates.NO_STATUS;
};
View on GitHub (pinned to 76a22dcba9)
Solutions
- Ensure TableNode children are exclusively TableRowNodes; remove any custom children or wrap them elsewhere.
- Re-read the anchor row within the same update and verify $isTableRowNode before inserting.
- If collaborating, ensure the Yjs table structure stays row-only (SyncV2 schema/registered nodes for tables are correct).
Example fix
// before
$insertTableRow(tableNode, idx, true, 1, dom);
// after
const rows = tableNode.getChildren();
if ($isTableRowNode(rows[idx])) {
$insertTableRow(tableNode, idx, true, 1, dom);
} Defensive patterns
Strategy: validation
Validate before calling
const anchor = tableNode.getChildren()[targetIndex]; if (!$isTableRowNode(anchor)) return; // malformed table, abort
Type guard
function rowExistsAt(tableNode: TableNode, idx: number): boolean {
return $isTableRowNode(tableNode.getChildren()[idx]);
} Try / catch
try {
$insertTableRow(tableNode, idx, true, 1, dom);
} catch (e) {
if (e.message.includes('Row before insertion index')) return;
throw e;
} Prevention
- Keep TableNode children exclusively TableRowNodes — never append arbitrary nodes to a TableNode
- Verify table structure after collaboration merges
- Run a structural sanity check ($isTableRowNode on every child) before bulk table ops
When it happens
Trigger: targetIndex valid numerically but tableRows[targetIndex] is not a TableRowNode — typically because the table's children were mutated into a non-row node, or targetIndex points at a child removed during the same update, or an empty children array combined with a range-check bypass.
Common situations: Custom nodes or transforms injected as direct children of TableNode; collaboration merges that desync the row list; calling insert while a prior transform in the same update removed the target row.
Related errors
- Expected TableNode.
- Expected table cell to be inside of table row.
- Expected table cell to be inside of table.
- Table row target index out of range
- Table column target index out of range
AI-assisted analysis of facebook/lexical@76a22dcba9 (2026-08-31).
Data as JSON: /api/errors/14f978ac8368c0ac.
Report an issue: GitHub.