{"record":{"id":"e23093e532f57ec2","repo":"immich-app/immich","slug":"email-is-not-available","errorCode":null,"errorMessage":"Email is not available","messagePattern":"Email is not available","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"server/src/services/base.service.ts","lineNumber":307,"sourceCode":"    return checkAccess(this.accessRepository, request);\n  }\n\n  async isSetupAvailable(): Promise<boolean> {\n    const { setup } = this.configRepository.getEnv();\n    return setup.allow && !(await this.userRepository.hasAdmin());\n  }\n\n  async requireSetupAvailable(): Promise<void> {\n    if (!(await this.isSetupAvailable())) {\n      throw new BadRequestException('Admin setup is not available');\n    }\n  }\n\n  async createUser(dto: Omit<Insertable<UserTable>, 'clusterGroupId'> & { email: string }): Promise<UserAdmin> {\n    const exists = await this.userRepository.getByEmail(dto.email);\n    if (exists) {\n      this.logger.debug('User creation rejected: user already exists');\n      throw new BadRequestException('Email is not available');\n    }\n\n    if (!dto.isAdmin) {\n      const localAdmin = await this.userRepository.getAdmin();\n      if (!localAdmin) {\n        throw new BadRequestException('The first registered account must the administrator.');\n      }\n    }\n\n    const payload: Omit<Insertable<UserTable>, 'clusterGroupId'> = { ...dto };\n    if (payload.password) {\n      payload.password = await this.cryptoRepository.hashBcrypt(payload.password, SALT_ROUNDS);\n    }\n    if (payload.storageLabel) {\n      payload.storageLabel = sanitize(payload.storageLabel.replaceAll('.', ''));\n    }\n\n    const clusterGroup = await this.clusterGroupRepository.create();","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/server/src/services/base.service.ts#L289-L325","documentation":"createUser enforces unique email addresses. It checks userRepository.getByEmail first and throws BadRequestException('Email is not available') if a user already exists with that email, before any insert happens.","triggerScenarios":"Admin user-creation, self-signup, or OAuth callback flows calling createUser with an email already registered (case/whitespace variants included).","commonSituations":"Duplicate signup attempts; OAuth accounts whose provider email matches an existing local user; bulk import re-run; trailing whitespace or case differences that still collide after normalization.","solutions":["Use a different email address for the new user","Have the existing account holder reset their password instead of creating a duplicate","Normalize the email (trim/lowercase) before checking and retry with a distinct value","Delete or rename the conflicting account first if it is stale"],"exampleFix":"// before\nawait service.createUser({ email: ' Bob@Example.com ', password });\n// after\nconst email = ' Bob@Example.com '.trim().toLowerCase();\nif (!(await service.userRepository.getByEmail(email))) await service.createUser({ email, password });","handlingStrategy":"validation","validationCode":"const email = raw.trim().toLowerCase(); if (await userRepository.getByEmail(email)) throw new Error('email taken');","typeGuard":null,"tryCatchPattern":"catch (e) { if (e.status === 400 && e.message === 'Email is not available') { /* offer password reset instead */ } }","preventionTips":["Normalize emails (trim/lowercase) before insert","Check uniqueness in the UI before submit","Prefer password reset over duplicate account creation"],"tags":["users","duplicate","email"],"backgroundTag":"record-already-exists","analyzedSha":"e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c","analyzedAt":"2026-09-15T07:20:19.675Z","contentChangedAt":"2026-09-15T07:20:19.675Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}