{"record":{"id":"19ed228e67ef9226","repo":"laurent22/joplin","slug":"user-is-required","errorCode":null,"errorMessage":"[user] is required","messagePattern":"\\[user\\] is required","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/app-cli/app/command-share.ts","lineNumber":261,"sourceCode":"\t\t\tconst ok = force ? true : await this.prompt(\n\t\t\t\t_('Unshare notebook \"%s\"? This may cause other users to lose access to the notebook.', folderTitle(folder)),\n\t\t\t\t{ booleanAnswerDefault: 'n' },\n\t\t\t);\n\t\t\tif (!ok) return;\n\n\t\t\tlogger.info('Unsharing folder', folder.id);\n\t\t\tawait ShareService.instance().unshareFolder(folder.id);\n\t\t\tawait reg.waitForSyncFinishedThenSync();\n\t\t};\n\n\t\tif (args.command === 'add' || args.command === 'remove' || args.command === 'delete') {\n\t\t\tif (!args.notebook) throw new Error('[notebook] is required');\n\t\t\tconst folder = await app().loadItemOrFail(ModelType.Folder, args.notebook);\n\n\t\t\tif (args.command === 'delete') {\n\t\t\t\treturn commandShareDelete(folder);\n\t\t\t} else {\n\t\t\t\tif (!args.user) throw new Error('[user] is required');\n\n\t\t\t\tconst email = args.user;\n\t\t\t\tif (args.command === 'add') {\n\t\t\t\t\treturn commandShareAdd(folder, email);\n\t\t\t\t} else if (args.command === 'remove') {\n\t\t\t\t\treturn commandShareRemove(folder, email);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (args.command === 'leave') {\n\t\t\tconst folder = args.notebook ? await app().loadItemOrFail(ModelType.Folder, args.notebook) : null;\n\n\t\t\tawait ShareService.instance().maintenance();\n\n\t\t\treturn CommandService.instance().execute(\n\t\t\t\t'leaveSharedFolder', folder?.id, { force: args.options.force },\n\t\t\t);","sourceCodeStart":243,"sourceCodeEnd":279,"githubUrl":"https://github.com/laurent22/joplin/blob/2654b33620775080d1d59c552259d41e33dad3d2/packages/app-cli/app/command-share.ts#L243-L279","documentation":"Thrown by the `share` command dispatcher after a notebook was resolved, when the subcommand is `add` or `remove` and no `[user]` argument was supplied. Both subcommands operate on a recipient identified by email, so the user argument is mandatory for them (but NOT for `delete`, which is why the guard sits in the else-branch).","triggerScenarios":"Running `:share add <notebook>` or `:share remove <notebook>` without the trailing email/user argument. The guard fires only after the notebook loads successfully, so a bad notebook errors earlier at error 48's path.","commonSituations":"Forgot the email argument; assumed `remove` with no user removes all recipients (it does not); scripting with an unset email variable.","solutions":["Re-run with the recipient email: `:share add <notebook> <email>` / `:share remove <notebook> <email>`.","If you want to unshare entirely (all recipients at once), use `:share delete <notebook>` instead.","When scripting, assert the email variable is set before invoking."],"exampleFix":"// before\nif (!args.user) throw new Error('[user] is required');\n\n// after - clarify the requirement and the delete alternative\nif (!args.user) throw new Error('[user] email is required for add/remove. Use \\`share delete <notebook>\\` to remove all recipients.');","handlingStrategy":"validation","validationCode":"if (['add','remove'].includes(command) && !args.user) {\n\tthrow new Error('[user] email is required for add/remove. Use \\`share delete\\` to remove all recipients.');\n}","typeGuard":"const isSubcommandRequiringUser = (c: string): boolean => ['add','remove'].includes(c);","tryCatchPattern":"try {\n\tawait app().executeCommand(['share', 'add', notebook, email]);\n} catch (e) {\n\tif (/\\[user\\] is required/.test(e.message)) { /* reprompt for email */ }\n\telse throw e;\n}","preventionTips":["Distinguish `remove` (one recipient) from `delete` (all recipients) in scripts.","Validate the email argument is non-empty before invoking add/remove.","Surface the `delete` alternative when no user is supplied."],"tags":["share","argument-validation","user","email","cli"],"backgroundTag":null,"analyzedSha":"2654b33620775080d1d59c552259d41e33dad3d2","analyzedAt":"2026-08-12T14:26:46.263Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}