laurent22/joplin · error · Error
Unknown command: ${cmd}
Error message
Unknown command: ${cmd} What it means
app-gui.ts dispatches internal GUI commands (triggered by keybindings, e.g. toggle_metadata, toggle_ids, enter_command_line_mode) through an if/else-if chain keyed on the command name. When the dispatched command string matches none of the branches, it throws 'Unknown command'. These are internal GUI action names, not user-typed CLI commands.
Source
Thrown at packages/app-cli/app/app-gui.ts:556
if (this.consoleIsMaximized()) {
this.hideConsole();
} else {
this.maximizeConsole();
}
}
} else if (cmd === 'toggle_metadata') {
this.toggleNoteMetadata();
} else if (cmd === 'toggle_ids') {
this.toggleFolderIds();
} else if (cmd === 'toggle_folder_collapse') {
this.toggleFolderCollapse();
} else if (cmd === 'enter_command_line_mode') {
const inputCmd = await this.widget('statusBar').prompt();
if (!inputCmd) return;
this.addCommandToConsole(inputCmd);
await this.processPromptCommand(inputCmd);
} else {
throw new Error(`Unknown command: ${cmd}`);
}
}
public async processPromptCommand(cmd: string) {
if (!cmd) return;
cmd = cmd.trim();
if (!cmd.length) return;
// this.logger().debug('Got command: ' + cmd);
try {
const note = this.widget('noteList').currentItem;
const folder = this.widget('folderList').currentItem;
const args = splitCommandString(cmd);
for (let i = 0; i < args.length; i++) {
if (args[i] === '$n') {
args[i] = note ? note.id : '';View on GitHub (pinned to 2654b33620)
Solutions
- Add the missing 'else if (cmd === "<name>") { ... }' branch that the dispatcher expects.
- Search the codebase for the command string to find which keybinding/config emits it and verify the spelling matches a branch.
- Refactor the if/else-if chain into a Map<string, handler> lookup so missing entries are caught at registration time rather than at dispatch.
Example fix
// before
// } else {
// throw new Error(`Unknown command: ${cmd}`);
// }
// after
// const handlers = { toggle_metadata: () => this.toggleNoteMetadata(), /* ... */ };
// const handler = handlers[cmd];
// if (!handler) throw new Error(`Unknown command: ${cmd}`);
// await handler.call(this); Defensive patterns
Strategy: validation
Validate before calling
const knownCommands = new Set(['toggle_metadata', 'toggle_ids', 'toggle_folder_collapse', 'enter_command_line_mode' /* ... */]);
if (!knownCommands.has(cmd)) {
console.warn(`Ignoring unknown GUI command: ${cmd}`);
return;
} Type guard
const isKnownGuiCommand = (cmd: string): boolean => ['toggle_metadata', 'toggle_ids', 'toggle_folder_collapse', 'enter_command_line_mode'].includes(cmd);
Try / catch
try {
await this.dispatchGuiCommand(cmd);
} catch (error) {
this.logger().warn('GUI command failed:', error.message);
} Prevention
- Prefer a Map<string, handler> dispatch table over an if/else-if chain so new commands are added in one place.
- When adding a keybinding, add the matching handler branch in the same commit.
- Unit-test that every keybinding command string has a corresponding handler.
When it happens
Trigger: A keybinding configuration or internal code calls this dispatch method with a command string that has no matching 'else if (cmd === ...)' branch — for example after adding a new keybinding but forgetting to add the handler, or after renaming a command without updating all references.
Common situations: Developer adds a keybinding that emits a new command name but omits the handler branch; a stale/imported keymap references a renamed command; a plugin injects a command name the GUI does not implement.
Related errors
AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12).
Data as JSON: /api/errors/dd63d8b5f0b97e58.
Report an issue: GitHub.