{"record":{"id":"7e870e71edc3f703","repo":"BookStackApp/BookStack","slug":"expected-to-find-tableelement-in-dom","errorCode":null,"errorMessage":"Expected to find TableElement in DOM","messagePattern":"Expected to find TableElement in DOM","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"resources/js/wysiwyg/lexical/table/LexicalTableObserver.ts","lineNumber":139,"sourceCode":"          if (\n            nodeName === 'TABLE' ||\n            nodeName === 'TBODY' ||\n            nodeName === 'THEAD' ||\n            nodeName === 'TR'\n          ) {\n            gridNeedsRedraw = true;\n            break;\n          }\n        }\n\n        if (!gridNeedsRedraw) {\n          return;\n        }\n\n        const tableElement = this.editor.getElementByKey(this.tableNodeKey);\n\n        if (!tableElement) {\n          throw new Error('Expected to find TableElement in DOM');\n        }\n\n        this.table = getTable(tableElement);\n      });\n    });\n    this.editor.update(() => {\n      const tableElement = this.editor.getElementByKey(this.tableNodeKey);\n\n      if (!tableElement) {\n        throw new Error('Expected to find TableElement in DOM');\n      }\n\n      this.table = getTable(tableElement);\n      observer.observe(tableElement, {\n        attributes: true,\n        childList: true,\n        subtree: true,\n      });","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/BookStackApp/BookStack/blob/18f8469a1c72f8cc8497e9372635e6dea5028071/resources/js/wysiwyg/lexical/table/LexicalTableObserver.ts#L121-L157","documentation":"TableObserver.trackTable runs an editor update that fetches the table's DOM element via editor.getElementByKey(this.tableNodeKey) to start observing it. If the element is not present in the DOM at that moment, it throws 'Expected to find TableElement in DOM'. The observer cannot function without the element it watches.","triggerScenarios":"Constructing a TableObserver (via the table selection plugin) for a table node whose DOM element has not yet been rendered, was removed, or belongs to a headless/unmounted editor.","commonSituations":"Programmatically creating table selections before the table renders (e.g. in initial editor state setup); tables removed by concurrent updates while an observer starts; test environments where the editor content is not flushed to the DOM.","solutions":["Defer observer/selection creation until after the table is rendered (e.g. in a useEffect or command listener post-mount).","Check editor.getElementByKey(tableNode.getKey()) for null before constructing a TableObserver.","Ensure the editor root is mounted in the document before initializing table selection state.","If the table may be deleted, guard lifecycle so observers are not created for detached nodes."],"exampleFix":"// before\nconst observer = new TableObserver(editor, tableNodeKey, ...); // throws if unmounted\n\n// after\nif (!editor.getElementByKey(tableNodeKey)) return;\nconst observer = new TableObserver(editor, tableNodeKey, ...);","handlingStrategy":"validation","validationCode":"if (!editor.getElementByKey(tableNodeKey)) {\n  // defer observer creation until rendered\n  return;\n}\nconst observer = new TableObserver(editor, tableNodeKey, ...);","typeGuard":null,"tryCatchPattern":"try {\n  new TableObserver(editor, tableNodeKey, ...);\n} catch (e) {\n  if (e instanceof Error && e.message === 'Expected to find TableElement in DOM') {\n    retryWhenMounted(() => new TableObserver(editor, tableNodeKey, ...));\n  } else throw e;\n}","preventionTips":["Create TableObservers only after the editor root is mounted and content flushed","Avoid creating observers for nodes that may be deleted concurrently","In tests, assert the table element exists in the DOM before selection setup"],"tags":["lexical","table","observer","dom","mounting"],"backgroundTag":"table-element-not-found","analyzedSha":"18f8469a1c72f8cc8497e9372635e6dea5028071","analyzedAt":"2026-09-02T19:49:33.068Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}