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

  1. Add the missing 'else if (cmd === "<name>") { ... }' branch that the dispatcher expects.
  2. Search the codebase for the command string to find which keybinding/config emits it and verify the spelling matches a branch.
  3. 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

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.