{"record":{"id":"770fdcc281dff71f","repo":"laurent22/joplin","slug":"there-is-already-a-user-with-this-email-user-email","errorCode":null,"errorMessage":"there is already a user with this email: ${user.email}","messagePattern":"there is already a user with this email: (.+?)","errorType":"validation","errorClass":"ErrorUnprocessableEntity","httpStatus":422,"severity":"error","filePath":"packages/server/src/models/UserModel.ts","lineNumber":475,"sourceCode":"\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> {\n\t// \tconst shares = await this.models().share().sharesByUser(id);\n\n\t// \tawait this.withTransaction(async () => {\n\t// \t\tawait this.models().item().deleteExclusivelyOwnedItems(id);\n\t// \t\tawait this.models().share().delete(shares.map(s => s.id));\n\t// \t\tawait this.models().userItem().deleteByUserId(id);\n\t// \t\tawait this.models().session().deleteByUserId(id);","sourceCodeStart":457,"sourceCodeEnd":493,"githubUrl":"https://github.com/laurent22/joplin/blob/981a03c5c9e88130bccff4db47c411d35ec7ae2c/packages/server/src/models/UserModel.ts#L457-L493","documentation":"UserModel.validate throws ErrorUnprocessableEntity('there is already a user with this email') when the email being saved is already owned by a different user. validate loads the user by email and only accepts the match if it is the same record (existingUser.id === user.id), so updating your own email to itself is allowed.","triggerScenarios":"Creating a new user with an email that already exists, or updating a user's email to one already taken by another account.","commonSituations":"Signup with an email that was previously registered; admin editing a user's email to a colleague's address; re-running an import script that creates duplicates.","solutions":["Choose a different email address for the account.","If the account exists, update/reuse the existing user record instead of creating a new one.","Check availability first via loadByEmail() before saving."],"exampleFix":"// before\nawait models.user().save({ email: 'taken@example.com', password: 'x' }, { isNew: true });\n// after\nconst existing = await models.user().loadByEmail('taken@example.com');\nif (existing) throw new Error('Email already registered');\nawait models.user().save({ email: 'taken@example.com', password: 'x' }, { isNew: true });","handlingStrategy":"try-catch","validationCode":"const existing = await models.user().loadByEmail(email); if (existing && existing.id !== userId) throw new Error('Email already in use');","typeGuard":null,"tryCatchPattern":"try { await models.user().save(user, opts); } catch (e) { if (/already a user with this email/.test(e.message)) /* show 'email taken' UI */; }","preventionTips":["Check email availability before creating accounts; reuse the existing record when appropriate.","Make import scripts idempotent by looking up users by email first."],"tags":["server","validation","duplicate"],"backgroundTag":"record-already-exists","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"}