{"record":{"id":"3a00e237987b5dfd","repo":"BookStackApp/BookStack","slug":"attempted-to-use-editoruicontext-before-it-has-bee","errorCode":null,"errorMessage":"Attempted to use EditorUIContext before it has been set","messagePattern":"Attempted to use EditorUIContext before it has been set","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"resources/js/wysiwyg/ui/framework/core.ts","lineNumber":43,"sourceCode":"\nexport function isUiBuilderDefinition(object: any): object is EditorUiBuilderDefinition {\n    return 'build' in object;\n}\n\nexport abstract class EditorUiElement {\n    protected dom: HTMLElement|null = null;\n    private context: EditorUiContext|null = null;\n    protected abortController: AbortController = new AbortController();\n\n    protected abstract buildDOM(): HTMLElement;\n\n    setContext(context: EditorUiContext): void {\n        this.context = context;\n    }\n\n    getContext(): EditorUiContext {\n        if (this.context === null) {\n            throw new Error('Attempted to use EditorUIContext before it has been set');\n        }\n\n        return this.context;\n    }\n\n    getDOMElement(): HTMLElement {\n        if (!this.dom) {\n            this.dom = this.buildDOM();\n        }\n\n        return this.dom;\n    }\n\n    rebuildDOM(): HTMLElement {\n        const newDOM = this.buildDOM();\n        this.dom?.replaceWith(newDOM);\n        this.dom = newDOM;\n        return this.dom;","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/BookStackApp/BookStack/blob/18f8469a1c72f8cc8497e9372635e6dea5028071/resources/js/wysiwyg/ui/framework/core.ts#L25-L61","documentation":"The WYSIWYG UI framework stores the EditorUiContext in a core singleton which starts as null. getContext() refuses to hand out an unset context because nearly every UI helper (toolbars, modals, translations via trans()) depends on it. Throwing here turns a silent null-dereference later into an immediate, diagnosable failure.","triggerScenarios":"Calling getContext() (directly or via trans(), modals, or any UI element) before setContext() has been called with a real EditorUiContext — e.g. rendering editor UI outside the editor bootstrap, or using a translate helper before the editor is created.","commonSituations":"Mounting WYSIWYG UI components in a page where the editor was never initialized (or init failed earlier), importing UI pieces into tests without a fixture context, calling UI code before the bootstrap completes, or an upgrade that moved context setup later in the boot sequence.","solutions":["Ensure setContext(editorUiContext) is called before any other UI framework usage — in the code that creates the editor UI.","Check initialization order: any code calling getContext() (directly or via trans()) must run after the editor bootstrap completes, not at module import time.","If rendering UI outside a real editor, construct a minimal EditorUiContext and pass it through setContext() first.","Defer context-dependent work until the editor setup/bootstrap callback has run."],"exampleFix":"// before\nimport { trans } from '../wysiwyg/ui/framework/core';\nconst label = trans('Bold'); // throws if editor not yet created\n\n// after\n// run inside the editor bootstrap callback, after setContext() has been called\nconst label = trans('Bold');","handlingStrategy":"validation","validationCode":"// Assert editor UI bootstrapped before using context-dependent APIs\nfunction assertUiReady(): void {\n    // flag set by the bootstrap right after setContext()\n    if (!window.__editorUiBootstrapped) {\n        throw new Error('Editor UI not initialized: setContext() has not run yet');\n    }\n}\nassertUiReady();\nconst ctx = getContext();","typeGuard":"function hasContext(core: { getContext(): EditorUiContext }): boolean {\n    try { return core.getContext() != null; } catch { return false; }\n}","tryCatchPattern":"try {\n    const ctx = getContext();\n    // use ctx\n} catch (e) {\n    if (e instanceof Error && e.message.includes('before it has been set')) {\n        // bootstrap not finished: defer or initialize first\n    } else { throw e; }\n}","preventionTips":["Call setContext() as the very first step of editor bootstrap, before any UI component renders.","Never use trans()/getContext() at module import time — only inside functions invoked after setup.","Expose an isReady/hasContext flag and gate UI code on it.","In tests, provide a shared fixture that always sets a context before importing UI helpers."],"tags":["initialization","lifecycle","null-context","wysiwyg"],"backgroundTag":"context-not-initialized","analyzedSha":"18f8469a1c72f8cc8497e9372635e6dea5028071","analyzedAt":"2026-09-02T19:49:33.068Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}