BookStackApp/BookStack · error · Error
Expected TableNode.
Error message
Expected TableNode.
What it means
TableObserver.clearHighlight clears the current table cell highlight inside an editor.update. It fetches the node by this.tableNodeKey and throws 'Expected TableNode.' if the node is missing or is no longer a TableNode ($isTableNode fails) — typically because the table was deleted or the key is stale.
Source
Thrown at resources/js/wysiwyg/lexical/table/LexicalTableObserver.ts:181
this.isHighlightingCells = false;
this.anchorX = -1;
this.anchorY = -1;
this.focusX = -1;
this.focusY = -1;
this.tableSelection = null;
this.anchorCellNodeKey = null;
this.focusCellNodeKey = null;
this.anchorCell = null;
this.focusCell = null;
this.hasHijackedSelectionStyles = false;
this.enableHighlightStyle();
editor.update(() => {
const tableNode = $getNodeByKey(this.tableNodeKey);
if (!$isTableNode(tableNode)) {
throw new Error('Expected TableNode.');
}
const tableElement = editor.getElementByKey(this.tableNodeKey);
if (!tableElement) {
throw new Error('Expected to find TableElement in DOM');
}
const grid = getTable(tableElement);
$updateDOMForSelection(editor, grid, null);
$setSelection(null);
editor.dispatchCommand(SELECTION_CHANGE_COMMAND, undefined);
});
}
enableHighlightStyle() {
const editor = this.editor;
editor.update(() => {View on GitHub (pinned to 18f8469a1c)
Solutions
- Check $getNodeByKey(this.tableNodeKey) with $isTableNode before calling clearHighlight, and skip if not a table.
- Tear down/dispose the TableObserver when the table node is removed so clearHighlight is never called on a dead key.
- Wrap clearHighlight in try/catch and treat the error as 'table already gone' (clear state, return).
- Revalidate the observer's key after undo/redo or history-driven state replacements.
Example fix
// before
observer.clearHighlight(); // throws after table deletion
// after
const node = $getNodeByKey(observer.tableNodeKey);
if ($isTableNode(node)) {
observer.clearHighlight();
} Defensive patterns
Strategy: type-guard
Validate before calling
const node = $getNodeByKey(observer.tableNodeKey); if (!$isTableNode(node)) return; // table deleted — skip highlight clearing
Type guard
function $isLiveTableNode(key: string): boolean {
return $isTableNode($getNodeByKey(key));
} Try / catch
try {
observer.clearHighlight();
} catch (e) {
if (e instanceof Error && (e.message === 'Expected TableNode.' || e.message === 'Expected to find TableElement in DOM')) {
return; // table already removed
}
throw e;
} Prevention
- Dispose observers when their table node is removed
- Validate the node key resolves to a TableNode before highlight updates
- Revalidate keys after undo/redo operations
When it happens
Trigger: Calling updateTableTableSelection (which calls clearHighlight) after the table node was removed from the editor state, or when the observer's tableNodeKey no longer resolves to a TableNode (node replaced by a different node type at the same key scenario, or null from $getNodeByKey).
Common situations: Deleting a table while it had an active cell selection/highlight then dispatching a selection update; stale observers kept alive after node removal; undo/redo replacing nodes and invalidating cached keys.
Related errors
- Cell not found in table.
- Expected to find TableElement in DOM
- Cell not found at cords.
- Node at cords not TableCellNode.
- Table Element Not Found
AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02).
Data as JSON: /api/errors/eb2540afc1859394.
Report an issue: GitHub.