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
- Re-run with the notebook title: `:share <subcommand> <notebook> [<user>]`.
- Check the usage string `share <command> [notebook] [user]` via `:help share`.
- 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 scripting, assert required positional args are non-empty before invoking.
- Keep the usage string `share <command> [notebook] [user]` visible.
- Validate the subcommand set early to give one clear error.
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
- No share found for folder ${folderId}
- No share found for folder ${folder.id}
- [user] is required
- Unknown subcommand: ${args.command}
- No notebook selected.
AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12).
Data as JSON: /api/errors/2b378a054fcf7c65.
Report an issue: GitHub.