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

  1. Normalize the table first so every row has the same cell count before column operations.
  2. Validate targetIndex against each row's getChildrenSize() (min across rows) before calling.
  3. Account for colSpan/rowSpan: compute the visual column index instead of using raw child indices from the DOM.
  4. 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

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


AI-assisted analysis of facebook/lexical@76a22dcba9 (2026-08-31). Data as JSON: /api/errors/16f317f0e831d9e0. Report an issue: GitHub.