laurent22/joplin · error · Error

The command "%s" is only available in GUI mode

Error message

The command "%s" is only available in GUI mode

What it means

Each command declares compatibleUis() (BaseCommand default is ['cli','gui']); GUI-only commands like 'search' override it to ['gui']. execCommand checks supportsUi('cli') and, when the app is running with a dummy GUI (pure CLI/scripting mode with no interactive terminal UI) and the command does not support 'cli', it throws 'The command ... is only available in GUI mode'. The message is i18n-translated.

Source

Thrown at packages/app-cli/app/app.ts:284

			hideModalOverlay: () => {},
			stdoutMaxWidth: () => {
				return 100;
			},
			forceRender: () => {},
			termSaveState: () => {},
			termRestoreState: () => {},
		};
	}

	public async execCommand(argv: string[]): Promise<void> {
		if (!argv.length) return this.execCommand(['help']);
		// reg.logger().debug('execCommand()', argv);
		const commandName = argv[0];
		this.activeCommand_ = this.findCommandByName(commandName);

		let outException = null;
		try {
			if (this.gui().isDummy() && !this.activeCommand_.supportsUi('cli')) throw new Error(_('The command "%s" is only available in GUI mode', this.activeCommand_.name()));
			const cmdArgs = cliUtils.makeCommandArgs(this.activeCommand_, argv);
			await this.activeCommand_.action(cmdArgs);
		} catch (error) {
			outException = error;
		}
		this.activeCommand_ = null;
		if (outException) throw outException;
	}

	public currentCommand() {
		return this.activeCommand_;
	}

	public async loadKeymaps() {
		interface KeyMapItem {
			keys: string[];
			type: 'function' | 'prompt';
			command: string;

View on GitHub (pinned to 2654b33620)

Solutions

  1. Run the command inside the interactive terminal GUI (launch 'joplin' without --batch).
  2. Use a CLI-compatible alternative command to achieve the same result.
  3. Check command.compatibleUis() before invoking to choose the right path.
  4. If you own the command, add 'cli' to compatibleUis() if the action truly works headless.

Example fix

// before
//   await app().execCommand(['search', 'foo']); // throws in CLI-only mode
// after
//   const cmd = app().findCommandByName('search');
//   if (!cmd.supportsUi('cli')) {
//     throw new Error(`Cannot run '${cmd.name()}' without a GUI`);
//   }
Defensive patterns

Strategy: validation

Validate before calling

const cmd = app().findCommandByName(name);
if (app().gui().isDummy() && !cmd.supportsUi('cli')) {
  throw new Error(`Command '${name}' requires the GUI; run it interactively.`);
}

Prevention

When it happens

Trigger: Invoking a GUI-only command (e.g. 'search', 'keymap', 'use') in a non-interactive context — a batch file, stdin pipe, the data API, or any mode where app().gui().isDummy() is true.

Common situations: Scripting Joplin via the data API or --batch with a command that only works in the terminal GUI; a command's compatibleUis() was narrowed in a version upgrade.

Related errors


AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12). Data as JSON: /api/errors/f67c59e336e488b3. Report an issue: GitHub.