BookStackApp/BookStack · error · Error
Attempted to show modal of key
Error message
Attempted to show modal of key [${key}] but no modal registered for that key What it means
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.
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.
Example fix
// before
manager.createModal('image-dialog'); // throws: no such key
// after
// in setup:
manager.addModal('image-dialog', imageModalDefinition);
// then:
const modal = manager.createModal('image-dialog'); // safe Defensive patterns
Strategy: validation
Validate before calling
// Validate the modal key exists before creating it
function modalExists(manager: EditorUiManager, key: string): boolean {
return manager.hasModal(key); // or keep your own Set of registered keys from addModal calls
}
if (!modalExists(manager, 'image-dialog')) {
console.warn('Modal not registered:', 'image-dialog');
return;
}
const modal = manager.createModal('image-dialog'); Try / catch
try {
const modal = manager.createModal(key);
} catch (e) {
if (e instanceof Error && e.message.includes('no modal registered for that key')) {
// extract missing key from message and register it, or fall back to a default dialog
} else { throw e; }
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Attempted to use EditorUIContext before it has been set
- Can't find options for dropdown menu
- Context attempted to be used without being set
- errors.import_zip_data_too_large
AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02).
Data as JSON: /api/errors/f5b1baabe327e819.
Report an issue: GitHub.
Appendix: source
Thrown at resources/js/wysiwyg/ui/framework/manager.ts:58
return this.context;
}
triggerStateUpdateForElement(element: EditorUiElement) {
element.updateState({
selection: null,
editor: this.getContext().editor
});
}
registerModal(key: string, modalDefinition: EditorFormModalDefinition) {
this.modalDefinitionsByKey[key] = modalDefinition;
}
createModal(key: string): EditorFormModal {
const modalDefinition = this.modalDefinitionsByKey[key];
if (!modalDefinition) {
throw new Error(`Attempted to show modal of key [${key}] but no modal registered for that key`);
}
const modal = new EditorFormModal(modalDefinition, key);
modal.setContext(this.getContext());
return modal;
}
setModalActive(key: string, modal: EditorFormModal): void {
this.activeModalsByKey[key] = modal;
}
setModalInactive(key: string): void {
delete this.activeModalsByKey[key];
}
getActiveModal(key: string): EditorFormModal|null {
return this.activeModalsByKey[key];View on GitHub (pinned to 18f8469a1c)