{"record":{"id":"179439c21bcff8ab","repo":"BookStackApp/BookStack","slug":"cell-not-found-in-table","errorCode":null,"errorMessage":"Cell not found in table.","messagePattern":"Cell not found in table\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"resources/js/wysiwyg/lexical/table/LexicalTableNode.ts","lineNumber":224,"sourceCode":"      if (row == null) {\n        continue;\n      }\n\n      const x = row.findIndex((cell) => {\n        if (!cell) {\n          return;\n        }\n        const {elem} = cell;\n        const cellNode = $getNearestNodeFromDOMNode(elem);\n        return cellNode === tableCellNode;\n      });\n\n      if (x !== -1) {\n        return {x, y};\n      }\n    }\n\n    throw new Error('Cell not found in table.');\n  }\n\n  getDOMCellFromCords(\n    x: number,\n    y: number,\n    table: TableDOMTable,\n  ): null | TableDOMCell {\n    const {domRows} = table;\n\n    const row = domRows[y];\n\n    if (row == null) {\n      return null;\n    }\n\n    const index = x < row.length ? x : row.length - 1;\n\n    const cell = row[index];","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/BookStackApp/BookStack/blob/18f8469a1c72f8cc8497e9372635e6dea5028071/resources/js/wysiwyg/lexical/table/LexicalTableNode.ts#L206-L242","documentation":"TableNode.getCordsFromCellNode maps a TableCellNode to its (x, y) grid coordinates by scanning the table's cell map. If the given cell node does not belong to this table (or its coordinates can't be resolved), no x is found and the method throws 'Cell not found in table.'","triggerScenarios":"Passing a TableCellNode from a different table, a cell node that has been removed/replaced in the DOM (stale key), or a cell whose row was deleted so it no longer appears in the grid map.","commonSituations":"Selection code holding a reference to a cell node from before a table mutation (insert/delete row/column); iterating cached nodes after an editor.update removed them; accidentally passing a cell from a nested/different table.","solutions":["Verify the TableCellNode belongs to the same TableNode (check its parent chain) before calling getCordsFromCellNode.","Re-read the cell node with $getNodeByKey inside the current update cycle instead of reusing cached references.","Use the non-throwing lookup (scan the grid yourself or use getCellNodeFromCords returning null) and handle the null case.","Recompute coordinates after any table structure mutation (row/column insert/delete)."],"exampleFix":"// before\nconst {x, y} = tableNode.getCordsFromCellNode(cellNode); // throws for foreign cell\n\n// after\nif ($isTableCellNode(cellNode) && cellNode.getParentTable() === tableNode) {\n  const {x, y} = tableNode.getCordsFromCellNode(cellNode);\n}","handlingStrategy":"type-guard","validationCode":"function cellBelongsToTable(cell: TableCellNode, table: TableNode): boolean {\n  let p = cell.getParent();\n  while (p) { if (p === table) return true; p = p.getParent(); }\n  return false;\n}","typeGuard":"function $isCellInTable(cell: LexicalNode | null | undefined, table: TableNode): cell is TableCellNode {\n  return $isTableCellNode(cell) && cell.getParentTable?.() === table;\n}","tryCatchPattern":"try {\n  const {x, y} = tableNode.getCordsFromCellNode(cellNode);\n} catch (e) {\n  if (e instanceof Error && e.message === 'Cell not found in table.') {\n    return null; // stale/foreign cell — recompute\n  }\n  throw e;\n}","preventionTips":["Re-read cell nodes via $getNodeByKey inside the current update instead of caching","Recompute coordinates after any row/column insert or delete","Verify parentage before cross-table operations"],"tags":["lexical","table","node-lookup","stale-reference"],"backgroundTag":"cell-not-found-in-table","analyzedSha":"18f8469a1c72f8cc8497e9372635e6dea5028071","analyzedAt":"2026-09-02T19:49:33.068Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}