{"record":{"id":"f5b1baabe327e819","repo":"BookStackApp/BookStack","slug":"attempted-to-show-modal-of-key-key-but-no-mod","errorCode":null,"errorMessage":"Attempted to show modal of key [${key}] but no modal registered for that key","messagePattern":"Attempted to show modal of key \\[(.+?)\\] but no modal registered for that key","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"resources/js/wysiwyg/ui/framework/manager.ts","lineNumber":58,"sourceCode":"\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];\n        if (!modalDefinition) {\n            throw new Error(`Attempted to show modal of key [${key}] but no modal registered for that key`);\n        }\n\n        const modal = new EditorFormModal(modalDefinition, key);\n        modal.setContext(this.getContext());\n\n        return modal;\n    }\n\n    setModalActive(key: string, modal: EditorFormModal): void {\n        this.activeModalsByKey[key] = modal;\n    }\n\n    setModalInactive(key: string): void {\n        delete this.activeModalsByKey[key];\n    }\n\n    getActiveModal(key: string): EditorFormModal|null {\n        return this.activeModalsByKey[key];","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/BookStackApp/BookStack/blob/18f8469a1c72f8cc8497e9372635e6dea5028071/resources/js/wysiwyg/ui/framework/manager.ts#L40-L76","documentation":"Modal definitions are registered per key via addModal (storing modalDefinitionsByKey[key]). createModal(key) throws when the requested key has no registered definition, because it cannot build an EditorFormModal without its definition. The key in the message identifies exactly which registration is missing.","triggerScenarios":"Calling createModal('someKey') where 'someKey' was never passed to addModal(), or the registration code never ran (plugin/config registering modals not loaded) — commonly from a toolbar button or editor action mapped to a stale/renamed modal key.","commonSituations":"A typo or rename mismatch between registration key and usage key; a custom build or feature flag omitting the plugin that registers the modal; upgrading the editor where built-in modal keys changed.","solutions":["Register the modal with the exact key before calling createModal: addModal(key, modalDefinition) in your editor setup.","Verify the key string matches character-for-character between registration and call site (compare with the key shown in the error message).","Ensure the plugin/config that registers built-in modals (e.g. link, table, media dialogs) is included in your editor configuration.","If the key comes from stored/user data, validate it against registered keys and fall back gracefully otherwise."],"exampleFix":"// before\nmanager.createModal('image-dialog'); // throws: no such key\n\n// after\n// in setup:\nmanager.addModal('image-dialog', imageModalDefinition);\n// then:\nconst modal = manager.createModal('image-dialog'); // safe","handlingStrategy":"validation","validationCode":"// Validate the modal key exists before creating it\nfunction modalExists(manager: EditorUiManager, key: string): boolean {\n    return manager.hasModal(key); // or keep your own Set of registered keys from addModal calls\n}\nif (!modalExists(manager, 'image-dialog')) {\n    console.warn('Modal not registered:', 'image-dialog');\n    return;\n}\nconst modal = manager.createModal('image-dialog');","typeGuard":null,"tryCatchPattern":"try {\n    const modal = manager.createModal(key);\n} catch (e) {\n    if (e instanceof Error && e.message.includes('no modal registered for that key')) {\n        // extract missing key from message and register it, or fall back to a default dialog\n    } else { throw e; }\n}","preventionTips":["Register every modal key in one central setup location and reference keys from a shared constants object to avoid typos.","Never hardcode modal key strings at call sites — import the same constant used at registration.","After editor upgrades, audit that all modal keys your toolbar/actions use are still registered.","Validate dynamic/stored modal keys against the registered set before calling createModal."],"tags":["modal","config","missing-key","wysiwyg"],"backgroundTag":"unregistered-modal-key","analyzedSha":"18f8469a1c72f8cc8497e9372635e6dea5028071","analyzedAt":"2026-09-02T19:49:33.068Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}