facebook/lexical · error
Table column target index out of range
Error message
Table column target index out of range
What it means
$insertTableColumn iterates every row and validates that targetIndex indexes an existing cell within that row's children. If any row has fewer cells than targetIndex+1 (or targetIndex is negative), it throws. This catches ragged tables where rows have unequal cell counts.
Source
Thrown at packages/lexical-table/src/LexicalTableUtils.ts:406
*/
export function $insertTableColumn(
tableNode: TableNode,
targetIndex: number,
shouldInsertAfter = true,
columnCount: number,
table: TableDOMTable,
): TableNode {
const tableRows = tableNode.getChildren();
const tableCellsToBeInserted = [];
for (let r = 0; r < tableRows.length; r++) {
const currentTableRowNode = tableRows[r];
if ($isTableRowNode(currentTableRowNode)) {
for (let c = 0; c < columnCount; c++) {
const tableRowChildren = currentTableRowNode.getChildren();
if (targetIndex >= tableRowChildren.length || targetIndex < 0) {
throw new Error('Table column target index out of range');
}
const targetCell = tableRowChildren[targetIndex];
invariant($isTableCellNode(targetCell), 'Expected table cell');
const {left, right} = $getTableCellSiblingsFromTableCellNode(
targetCell,
table,
);
let headerState = TableCellHeaderStates.NO_STATUS;
if (
(left && left.hasHeaderState(TableCellHeaderStates.ROW)) ||
(right && right.hasHeaderState(TableCellHeaderStates.ROW))
) {
headerState |= TableCellHeaderStates.ROW;View on GitHub (pinned to 76a22dcba9)
Solutions
- Normalize the table first so every row has the same cell count before column operations.
- Validate targetIndex against each row's getChildrenSize() (min across rows) before calling.
- Account for colSpan/rowSpan: compute the visual column index instead of using raw child indices from the DOM.
- Repair ragged tables by appending empty cells to short rows in the same update.
Example fix
// before
const minCells = Math.min(...tableNode.getChildren().map(r => r.getChildrenSize()));
$insertTableColumn(tableNode, targetIndex, true, 1, grid);
// after
const minCells = Math.min(...tableNode.getChildren().map(r => r.getChildrenSize()));
if (targetIndex < minCells) {
$insertTableColumn(tableNode, targetIndex, true, 1, grid);
} Defensive patterns
Strategy: validation
Validate before calling
const rows = tableNode.getChildren().filter($isTableRowNode); const minCells = Math.min(...rows.map(r => r.getChildrenSize())); if (targetIndex < 0 || targetIndex >= minCells) return;
Type guard
function isColumnTargetValid(tableNode: TableNode, idx: number): boolean {
const rows = tableNode.getChildren().filter($isTableRowNode);
return rows.length > 0 && idx >= 0 &&
idx <= Math.min(...rows.map(r => r.getChildrenSize()));
} Try / catch
try {
$insertTableColumn(tableNode, idx, true, 1, grid);
} catch (e) {
if (e.message.includes('column target index')) normalizeTable(tableNode); // pad ragged rows
else throw e;
} Prevention
- Normalize ragged tables (equal cell counts per row) before column operations
- Account for colSpan/rowSpan when converting DOM positions to cell indices
- Add/repair missing cells in short rows inside the same update
When it happens
Trigger: Inserting a column at an index beyond a particular row's cell count — commonly caused by rows that already have differing numbers of cells (merged/removed cells, colSpans, or a malformed table built programmatically).
Common situations: Tables hand-built with $createTableCellNode where some rows got fewer cells; removing cells from one row earlier without fixing others; DOM-derived target index that doesn't account for colSpan'd cells.
Related errors
- Table row target index out of range
- Expected TableNode.
- Expected table cell to be inside of table row.
- Expected table cell to be inside of table.
- Row before insertion index does not exist.
AI-assisted analysis of facebook/lexical@76a22dcba9 (2026-08-31).
Data as JSON: /api/errors/16f317f0e831d9e0.
Report an issue: GitHub.