laurent22/joplin · error · Error

[notebook] is required

Error message

[notebook] is required

What it means

Thrown by the `share` command dispatcher when the subcommand is `add`, `remove`, or `delete` but no `[notebook]` argument was supplied. These three subcommands all require a target notebook to act on, so the argument is mandatory. The message echoes the CLI syntax token `[notebook]` so the user knows which slot is missing.

Source

Thrown at packages/app-cli/app/command-share.ts:255

		const commandShareReject = (folderId: string) => (
			commandShareAcceptOrReject(folderId, false)
		);

		const commandShareDelete = async (folder: FolderEntity) => {
			const force = args.options.force;
			const ok = force ? true : await this.prompt(
				_('Unshare notebook "%s"? This may cause other users to lose access to the notebook.', folderTitle(folder)),
				{ booleanAnswerDefault: 'n' },
			);
			if (!ok) return;

			logger.info('Unsharing folder', folder.id);
			await ShareService.instance().unshareFolder(folder.id);
			await reg.waitForSyncFinishedThenSync();
		};

		if (args.command === 'add' || args.command === 'remove' || args.command === 'delete') {
			if (!args.notebook) throw new Error('[notebook] is required');
			const folder = await app().loadItemOrFail(ModelType.Folder, args.notebook);

			if (args.command === 'delete') {
				return commandShareDelete(folder);
			} else {
				if (!args.user) throw new Error('[user] is required');

				const email = args.user;
				if (args.command === 'add') {
					return commandShareAdd(folder, email);
				} else if (args.command === 'remove') {
					return commandShareRemove(folder, email);
				}
			}
		}

		if (args.command === 'leave') {
			const folder = args.notebook ? await app().loadItemOrFail(ModelType.Folder, args.notebook) : null;

View on GitHub (pinned to 2654b33620)

Solutions

  1. Re-run with the notebook title: `:share <subcommand> <notebook> [<user>]`.
  2. Check the usage string `share <command> [notebook] [user]` via `:help share`.
  3. When scripting, assert the notebook variable is non-empty before invoking the command.

Example fix

// before
if (!args.notebook) throw new Error('[notebook] is required');

// after - point to usage
if (!args.notebook) throw new Error('[notebook] is required. Usage: share <command> [notebook] [user]');
Defensive patterns

Strategy: validation

Validate before calling

if (['add','remove','delete'].includes(command) && !args.notebook) {
	throw new Error('[notebook] is required. Usage: share <command> [notebook] [user]');
}

Type guard

const isSubcommandRequiringNotebook = (c: string): boolean => ['add','remove','delete'].includes(c);

Try / catch

try {
	await app().executeCommand(['share', subcommand, notebook, user].filter(Boolean));
} catch (e) {
	if (/\[notebook\] is required/.test(e.message)) { /* reprompt for notebook */ }
	else throw e;
}

Prevention

When it happens

Trigger: Running `:share add`, `:share remove`, or `:share delete` without a following notebook argument. Because the command parses positionally, an empty or whitespace-only notebook value also trips this guard.

Common situations: Forgot the notebook argument; copy-paste truncated the command; scripting the CLI with an unset variable for the notebook.

Related errors


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