{"record":{"id":"35c403a849e8db9b","repo":"BookStackApp/BookStack","slug":"context-attempted-to-be-used-without-being-set","errorCode":null,"errorMessage":"Context attempted to be used without being set","messagePattern":"Context attempted to be used without being set","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"resources/js/wysiwyg/ui/framework/manager.ts","lineNumber":38,"sourceCode":"    protected decoratorInstancesByNodeKey: Record<string, EditorDecorator> = {};\n    protected context: EditorUiContext|null = null;\n    protected toolbar: EditorContainerUiElement|null = null;\n    protected contextToolbarDefinitionsByKey: Record<string, EditorContextToolbarDefinition> = {};\n    protected activeContextToolbars: EditorContextToolbar[] = [];\n    protected selectionChangeHandlers: Set<SelectionChangeHandler> = new Set();\n    protected domEventAbortController = new AbortController();\n    protected teardownCallbacks: (()=>void)[] = [];\n\n    setContext(context: EditorUiContext) {\n        this.context = context;\n        this.setupEventListeners();\n        this.setupEditor(context.editor, context);\n        this.dropdowns.setIsRTL(this.context.manager.getDefaultDirection() === 'rtl');\n    }\n\n    getContext(): EditorUiContext {\n        if (this.context === null) {\n            throw new Error(`Context attempted to be used without being set`);\n        }\n\n        return this.context;\n    }\n\n    triggerStateUpdateForElement(element: EditorUiElement) {\n        element.updateState({\n            selection: null,\n            editor: this.getContext().editor\n        });\n    }\n\n    registerModal(key: string, modalDefinition: EditorFormModalDefinition) {\n        this.modalDefinitionsByKey[key] = modalDefinition;\n    }\n\n    createModal(key: string): EditorFormModal {\n        const modalDefinition = this.modalDefinitionsByKey[key];","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/BookStackApp/BookStack/blob/18f8469a1c72f8cc8497e9372635e6dea5028071/resources/js/wysiwyg/ui/framework/manager.ts#L20-L56","documentation":"The EditorUiManager holds the shared EditorUiContext, initially null, and is configured via the setup path that also wires the editor and dropdown RTL state. getContext() throws if accessed before configuration, since every manager feature (modals, toolbars, state refresh, decorators) requires the context. This fails fast instead of cascading null errors.","triggerScenarios":"Calling getContext() — directly or indirectly via triggerStateUpdateForElement(), createModal(), decorator(), setToolbar(), the editor accessor, or triggerFutureStateRefresh() — before the manager has been given an EditorUiContext.","commonSituations":"Accessing manager.editor or manager.decorator(...) at module scope before the editor UI is bootstrapped; building toolbar/modal objects where editor init was skipped or failed; tests instantiating the manager without a context fixture.","solutions":["Initialize the manager by setting its context (the setup path that wires context.editor) before touching manager APIs.","Defer manager-dependent code (setToolbar, createModal, triggerStateUpdateForElement) until after editor bootstrap completes.","In tests or custom integrations, construct a full EditorUiContext and assign it first.","Gate manager access on an is-configured check and queue work until setup runs."],"exampleFix":"// before\nconst manager = ui.getManager();\nmanager.setToolbar(toolbar); // throws: context not yet set\n\n// after\n// run after editor bootstrap has configured the manager\nconst manager = ui.getManager();\nmanager.setToolbar(toolbar); // safe","handlingStrategy":"validation","validationCode":"// Gate manager usage on manager setup having completed\nfunction managerIsConfigured(manager: EditorUiManager): boolean {\n    try {\n        manager.getContext();\n        return true;\n    } catch {\n        return false;\n    }\n}\nif (managerIsConfigured(manager)) {\n    manager.setToolbar(toolbar);\n}","typeGuard":"function withContext<T>(manager: EditorUiManager, fn: (ctx: EditorUiContext) => T): T | null {\n    try { return fn(manager.getContext()); } catch { return null; }\n}","tryCatchPattern":"try {\n    manager.setToolbar(toolbar);\n} catch (e) {\n    if (e instanceof Error && e.message.includes('without being set')) {\n        // manager not configured yet: run this after editor bootstrap instead\n    } else { throw e; }\n}","preventionTips":["Run all manager API calls inside the editor bootstrap/setup flow, never at module scope.","Keep a single ownership point for calling the manager's context setup.","In tests, build a full EditorUiContext fixture before instantiating manager-dependent objects.","Queue manager-dependent work (toolbars, modals) until setup has signaled completion."],"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"}