{"record":{"id":"cd998bb80558701b","repo":"BookStackApp/BookStack","slug":"attempted-to-get-use-node-without-it-being-set","errorCode":null,"errorMessage":"Attempted to get use node without it being set","messagePattern":"Attempted to get use node without it being set","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"resources/js/wysiwyg/ui/framework/decorator.ts","lineNumber":22,"sourceCode":"export interface EditorDecoratorAdapter {\n    type: string;\n    getNode(): LexicalNode;\n}\n\nexport abstract class EditorDecorator {\n\n    protected node: LexicalNode | null = null;\n    protected context: EditorUiContext;\n\n    private onDestroyCallbacks: (() => void)[] = [];\n\n    constructor(context: EditorUiContext) {\n        this.context = context;\n    }\n\n    protected getNode(): LexicalNode {\n        if (!this.node) {\n            throw new Error('Attempted to get use node without it being set');\n        }\n\n        return this.node;\n    }\n\n    setNode(node: LexicalNode) {\n        this.node = node;\n    }\n\n    /**\n     * Register a callback to be ran on destroy of this decorator's node.\n     */\n    protected onDestroy(callback: () => void) {\n        this.onDestroyCallbacks.push(callback);\n    }\n\n    /**\n     * Render the decorator.","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/BookStackApp/BookStack/blob/18f8469a1c72f8cc8497e9372635e6dea5028071/resources/js/wysiwyg/ui/framework/decorator.ts#L4-L40","documentation":"Decorator UI subclasses wrap a LexicalNode, which is assigned via setNode(). The protected getNode() accessor throws if the node was never set, preventing decorators from operating on an undefined node. This is an internal lifecycle contract: construct -> setNode -> render/update.","triggerScenarios":"Calling a method on an EditorUiDecorator subclass that internally calls getNode() before setNode(node) was invoked — e.g. creating a decorator instance manually and using it before assignment, or the framework invoking decorator hooks on an instance whose node assignment was skipped.","commonSituations":"Custom decorator subclasses that break the lifecycle and forget to call setNode; instantiating a decorator by hand in tests or custom UI code without wiring it to a node; a Lexical transform that constructs the decorator but errors before node assignment.","solutions":["Always call setNode(node) on a decorator immediately after construction, before any other interaction.","In custom decorator code, use setNode() or the framework's creation path instead of relying on a default node value.","Check that the Lexical transform/import logic creating the decorator completes node assignment before rendering.","Guard custom code against using the decorator during its setup phase."],"exampleFix":"// before\nconst decorator = new MyDecorator(context);\ndecorator.update(); // getNode() throws\n\n// after\nconst decorator = new MyDecorator(context);\ndecorator.setNode(theLexicalNode);\ndecorator.update(); // safe","handlingStrategy":"type-guard","validationCode":"// Only interact with a decorator once its node has been assigned\nfunction decoratorHasNode(d: EditorUiDecorator): boolean {\n    return (d as unknown as { node?: LexicalNode | null }).node != null;\n}\nif (decoratorHasNode(decorator)) {\n    decorator.update();\n}","typeGuard":"function hasNode(d: EditorUiDecorator): d is EditorUiDecorator & { node: LexicalNode } {\n    return (d as unknown as { node?: LexicalNode | null }).node != null;\n}\nif (hasNode(decorator)) { decorator.update(); }","tryCatchPattern":"try {\n    decorator.update();\n} catch (e) {\n    if (e instanceof Error && e.message.includes('use node without it being set')) {\n        decorator.setNode(someLexicalNode);\n        decorator.update();\n    } else { throw e; }\n}","preventionTips":["Call setNode() immediately after constructing a decorator, before any rendering/update call.","Never instantiate decorators manually outside the framework's node-creation path.","In custom subclasses, keep the construct -> setNode -> use order intact.","Add a test asserting every decorator creation path assigns a node before first use."],"tags":["lifecycle","lexical","decorator","null-value"],"backgroundTag":"node-not-set","analyzedSha":"18f8469a1c72f8cc8497e9372635e6dea5028071","analyzedAt":"2026-09-02T19:49:33.068Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}