{"record":{"id":"e1351caccfe124e0","repo":"laurent22/joplin","slug":"email-must-be-set","errorCode":null,"errorMessage":"email must be set","messagePattern":"email must be set","errorType":"validation","errorClass":"ErrorUnprocessableEntity","httpStatus":422,"severity":"error","filePath":"packages/server/src/models/UserModel.ts","lineNumber":468,"sourceCode":"\t\t\tlet msg: string[] = [result.feedback.warning];\n\t\t\tif (result.feedback.suggestions) {\n\t\t\t\tmsg = msg.concat(result.feedback.suggestions);\n\t\t\t}\n\t\t\tthrow new ErrorUnprocessableEntity(msg.join(' '));\n\t\t}\n\t}\n\n\tprotected async validate(object: User, options: ValidateOptions = {}): Promise<User> {\n\t\tconst user: User = await super.validate(object, options);\n\n\t\t// Note that we don't validate the password here because it's already\n\t\t// been hashed by then.\n\t\tif (options.isNew) {\n\t\t\tif (!user.email) throw new ErrorUnprocessableEntity('email must be set');\n\t\t\tif ('email' in user && !user.email.includes('@')) throw new ErrorUnprocessableEntity(`Should include @ in email address, email: ${user.email}`);\n\t\t\tif (!user.password && !user.must_set_password) throw new ErrorUnprocessableEntity('password must be set');\n\t\t} else {\n\t\t\tif ('email' in user && !user.email) throw new ErrorUnprocessableEntity('email must be set');\n\t\t\tif (user.email && !user.email.includes('@')) throw new ErrorUnprocessableEntity(`Should include @ in email address, email: ${user.email}`);\n\t\t\tif ('password' in user && !user.password) throw new ErrorUnprocessableEntity('password must be set');\n\t\t}\n\n\t\tif (user.email) {\n\t\t\tconst existingUser = await this.loadByEmail(user.email);\n\t\t\tif (existingUser && existingUser.id !== user.id) throw new ErrorUnprocessableEntity(`there is already a user with this email: ${user.email}`);\n\t\t\t// See https://www.rfc-editor.org/errata_search.php?rfc=3696&eid=1690 (found via https://stackoverflow.com/a/574698)\n\t\t\tif (user.email.length > 254) throw new ErrorUnprocessableEntity('Please enter an email address between 0 and 254 characters');\n\t\t\tvalidateEmail(user.email);\n\t\t}\n\n\t\tif (user.full_name && user.full_name.length > 256) throw new ErrorUnprocessableEntity('Full name must be at most 256 characters');\n\n\t\treturn super.validate(user, options);\n\t}\n\n\t// public async delete(id: string): Promise<void> {","sourceCodeStart":450,"sourceCodeEnd":486,"githubUrl":"https://github.com/laurent22/joplin/blob/981a03c5c9e88130bccff4db47c411d35ec7ae2c/packages/server/src/models/UserModel.ts#L450-L486","documentation":"UserModel.validate throws ErrorUnprocessableEntity('email must be set') when a user record is saved without an email address. For new users (isNew) an email is always required; for updates it is required only if the 'email' key is present in the object being saved (i.e. you explicitly tried to set a falsy email).","triggerScenarios":"Saving a new user (isNew: true) with no email, or patching a user with { email: '' } / { email: null }.","commonSituations":"Signup or admin-create flows where the form did not include the email field; bulk import code omitting the email column; a PATCH request explicitly blanking the email.","solutions":["Provide a valid email address when creating the user.","On update requests, omit the email key entirely if you do not intend to change it.","Validate form input before calling save() to ensure email is non-empty."],"exampleFix":"// before\nawait models.user().save({ password: 'x', must_set_password: true }, { isNew: true });\n// after\nawait models.user().save({ email: 'user@example.com', password: 'x', must_set_password: true }, { isNew: true });","handlingStrategy":"validation","validationCode":"if (!email) throw new Error('email is required');","typeGuard":"function hasEmail(u: { email?: string }): u is { email: string } & typeof u { return typeof u.email === 'string' && u.email.length > 0; }","tryCatchPattern":"try { await models.user().save(user, opts); } catch (e) { if (e.message === 'email must be set') /* surface field-level error to form */; }","preventionTips":["Mark email as required in signup/creation forms and validate before submit.","On PATCH requests, only include the email key when actually changing it."],"tags":["server","validation","user-model"],"backgroundTag":"missing-required-argument","analyzedSha":"981a03c5c9e88130bccff4db47c411d35ec7ae2c","analyzedAt":"2026-09-17T14:49:40.960Z","contentChangedAt":"2026-09-17T14:49:40.960Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}