BookStackApp/BookStack · error · Error

Attempted to get use node without it being set

Error message

Attempted to get use node without it being set

What it means

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.

Source

Thrown at resources/js/wysiwyg/ui/framework/decorator.ts:22

export interface EditorDecoratorAdapter {
    type: string;
    getNode(): LexicalNode;
}

export abstract class EditorDecorator {

    protected node: LexicalNode | null = null;
    protected context: EditorUiContext;

    private onDestroyCallbacks: (() => void)[] = [];

    constructor(context: EditorUiContext) {
        this.context = context;
    }

    protected getNode(): LexicalNode {
        if (!this.node) {
            throw new Error('Attempted to get use node without it being set');
        }

        return this.node;
    }

    setNode(node: LexicalNode) {
        this.node = node;
    }

    /**
     * Register a callback to be ran on destroy of this decorator's node.
     */
    protected onDestroy(callback: () => void) {
        this.onDestroyCallbacks.push(callback);
    }

    /**
     * Render the decorator.

View on GitHub (pinned to 18f8469a1c)

Solutions

  1. Always call setNode(node) on a decorator immediately after construction, before any other interaction.
  2. In custom decorator code, use setNode() or the framework's creation path instead of relying on a default node value.
  3. Check that the Lexical transform/import logic creating the decorator completes node assignment before rendering.
  4. Guard custom code against using the decorator during its setup phase.

Example fix

// before
const decorator = new MyDecorator(context);
decorator.update(); // getNode() throws

// after
const decorator = new MyDecorator(context);
decorator.setNode(theLexicalNode);
decorator.update(); // safe
Defensive patterns

Strategy: type-guard

Validate before calling

// Only interact with a decorator once its node has been assigned
function decoratorHasNode(d: EditorUiDecorator): boolean {
    return (d as unknown as { node?: LexicalNode | null }).node != null;
}
if (decoratorHasNode(decorator)) {
    decorator.update();
}

Type guard

function hasNode(d: EditorUiDecorator): d is EditorUiDecorator & { node: LexicalNode } {
    return (d as unknown as { node?: LexicalNode | null }).node != null;
}
if (hasNode(decorator)) { decorator.update(); }

Try / catch

try {
    decorator.update();
} catch (e) {
    if (e instanceof Error && e.message.includes('use node without it being set')) {
        decorator.setNode(someLexicalNode);
        decorator.update();
    } else { throw e; }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02). Data as JSON: /api/errors/cd998bb80558701b. Report an issue: GitHub.