{"record":{"id":"02598f32e876a0e5","repo":"facebook/lexical","slug":"expected-table-cell-to-be-inside-of-table-row","errorCode":null,"errorMessage":"Expected table cell to be inside of table row.","messagePattern":"Expected table cell to be inside of table row\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/lexical-table/src/LexicalTableUtils.ts","lineNumber":116,"sourceCode":"  const node = $findMatchingParent(startingNode, n => $isTableCellNode(n));\n\n  if ($isTableCellNode(node)) {\n    return node;\n  }\n\n  return null;\n}\n\nexport function $getTableRowNodeFromTableCellNodeOrThrow(\n  startingNode: LexicalNode,\n): TableRowNode {\n  const node = $findMatchingParent(startingNode, n => $isTableRowNode(n));\n\n  if ($isTableRowNode(node)) {\n    return node;\n  }\n\n  throw new Error('Expected table cell to be inside of table row.');\n}\n\nexport function $getTableNodeFromLexicalNodeOrThrow(\n  startingNode: LexicalNode,\n): TableNode {\n  const node = $findMatchingParent(startingNode, n => $isTableNode(n));\n\n  if ($isTableNode(node)) {\n    return node;\n  }\n\n  throw new Error('Expected table cell to be inside of table.');\n}\n\nexport function $getTableRowIndexFromTableCellNode(\n  tableCellNode: TableCellNode,\n): number {\n  const tableRowNode = $getTableRowNodeFromTableCellNodeOrThrow(tableCellNode);","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/facebook/lexical/blob/76a22dcba981b46119fcec45f935270707e26a57/packages/lexical-table/src/LexicalTableUtils.ts#L98-L134","documentation":"$getTableRowNodeOrThrow walks up the node tree from a starting node searching for a TableRowNode. If no ancestor is a table row, the node is not actually inside a table's row structure, and the function throws instead of returning null (the $...OrThrow contract).","triggerScenarios":"Calling $getTableRowIndexFromTableCellNode, $getTableRowNodeFromTableCellNodeOrThrow, or related helpers with a node that is detached, a TableCellNode that was removed from its row, or a node of the wrong type entirely.","commonSituations":"Operating on a table cell captured before an update that removed the row; passing nodes from a cloned/stale EditorState; calling helpers outside the real table hierarchy (e.g. on cells built ad hoc and never appended to a row).","solutions":["Verify the cell is attached to a live row before calling: check $isTableRowNode(cell.getParent()) or use the non-throwing $findMatchingParent scan yourself.","Re-fetch the cell from the current editor state (via $getNodeByKey or selection) instead of using a stored reference.","Wrap the call in try/catch if detachment is an expected condition and handle the fallback path."],"exampleFix":"// before\nconst row = $getTableRowNodeFromTableCellNodeOrThrow(staleCell);\n// after\nconst cell = $getNodeByKey(staleCell.getKey());\nif ($isTableCellNode(cell) && $isTableRowNode(cell.getParent())) {\n  const row = $getTableRowNodeFromTableCellNodeOrThrow(cell);\n}","handlingStrategy":"type-guard","validationCode":"if (!$isTableCellNode(cell) || !$isTableRowNode(cell.getParent())) return null;","typeGuard":"function isInTableRow(node: LexicalNode): node is TableCellNode {\n  return $isTableCellNode(node) && $isTableRowNode(node.getParent());\n}","tryCatchPattern":"try {\n  return $getTableRowNodeFromTableCellNodeOrThrow(cell);\n} catch {\n  return null; // cell detached from any row\n}","preventionTips":["Re-fetch nodes via $getNodeByKey inside the current update instead of caching","Prefer the non-throwing $getTableNodeFromLexicalNode variants when detachment is possible","Keep table operations atomic within a single editor.update"],"tags":["lexical-table","detached-node","hierarchy"],"backgroundTag":"detached-node-hierarchy","analyzedSha":"76a22dcba981b46119fcec45f935270707e26a57","analyzedAt":"2026-08-31T21:45:54.792Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}