{"record":{"id":"16f317f0e831d9e0","repo":"facebook/lexical","slug":"table-column-target-index-out-of-range","errorCode":null,"errorMessage":"Table column target index out of range","messagePattern":"Table column target index out of range","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/lexical-table/src/LexicalTableUtils.ts","lineNumber":406,"sourceCode":" */\nexport function $insertTableColumn(\n  tableNode: TableNode,\n  targetIndex: number,\n  shouldInsertAfter = true,\n  columnCount: number,\n  table: TableDOMTable,\n): TableNode {\n  const tableRows = tableNode.getChildren();\n\n  const tableCellsToBeInserted = [];\n  for (let r = 0; r < tableRows.length; r++) {\n    const currentTableRowNode = tableRows[r];\n\n    if ($isTableRowNode(currentTableRowNode)) {\n      for (let c = 0; c < columnCount; c++) {\n        const tableRowChildren = currentTableRowNode.getChildren();\n        if (targetIndex >= tableRowChildren.length || targetIndex < 0) {\n          throw new Error('Table column target index out of range');\n        }\n\n        const targetCell = tableRowChildren[targetIndex];\n\n        invariant($isTableCellNode(targetCell), 'Expected table cell');\n\n        const {left, right} = $getTableCellSiblingsFromTableCellNode(\n          targetCell,\n          table,\n        );\n\n        let headerState = TableCellHeaderStates.NO_STATUS;\n\n        if (\n          (left && left.hasHeaderState(TableCellHeaderStates.ROW)) ||\n          (right && right.hasHeaderState(TableCellHeaderStates.ROW))\n        ) {\n          headerState |= TableCellHeaderStates.ROW;","sourceCodeStart":388,"sourceCodeEnd":424,"githubUrl":"https://github.com/facebook/lexical/blob/76a22dcba981b46119fcec45f935270707e26a57/packages/lexical-table/src/LexicalTableUtils.ts#L388-L424","documentation":"$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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nconst minCells = Math.min(...tableNode.getChildren().map(r => r.getChildrenSize()));\n$insertTableColumn(tableNode, targetIndex, true, 1, grid);\n// after\nconst minCells = Math.min(...tableNode.getChildren().map(r => r.getChildrenSize()));\nif (targetIndex < minCells) {\n  $insertTableColumn(tableNode, targetIndex, true, 1, grid);\n}","handlingStrategy":"validation","validationCode":"const rows = tableNode.getChildren().filter($isTableRowNode);\nconst minCells = Math.min(...rows.map(r => r.getChildrenSize()));\nif (targetIndex < 0 || targetIndex >= minCells) return;","typeGuard":"function isColumnTargetValid(tableNode: TableNode, idx: number): boolean {\n  const rows = tableNode.getChildren().filter($isTableRowNode);\n  return rows.length > 0 && idx >= 0 &&\n    idx <= Math.min(...rows.map(r => r.getChildrenSize()));\n}","tryCatchPattern":"try {\n  $insertTableColumn(tableNode, idx, true, 1, grid);\n} catch (e) {\n  if (e.message.includes('column target index')) normalizeTable(tableNode); // pad ragged rows\n  else throw e;\n}","preventionTips":["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"],"tags":["lexical-table","index-out-of-range","ragged-table"],"backgroundTag":"index-out-of-range","analyzedSha":"76a22dcba981b46119fcec45f935270707e26a57","analyzedAt":"2026-08-31T21:45:54.792Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}