{"record":{"id":"4f63f5cfebf0f691","repo":"immich-app/immich","slug":"email-is-not-available-4f63f5","errorCode":null,"errorMessage":"Email is not available","messagePattern":"Email is not available","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"server/src/services/user.service.ts","lineNumber":61,"sourceCode":"  async getMe(auth: AuthDto): Promise<UserAdminResponseDto> {\n    const user = await this.userRepository.get(auth.user.id, {});\n    if (!user) {\n      throw new BadRequestException('User not found');\n    }\n\n    return mapUserAdmin(user);\n  }\n\n  getCalendarHeatmap(auth: AuthDto, dto: CalendarHeatmapDto): Promise<CalendarHeatmapResponseDto> {\n    return getCalendarHeatmap(auth.user.id, dto, { asset: this.assetRepository });\n  }\n\n  async updateMe({ user }: AuthDto, dto: UserUpdateMeDto): Promise<UserAdminResponseDto> {\n    if (dto.email) {\n      const duplicate = await this.userRepository.getByEmail(dto.email);\n      if (duplicate && duplicate.id !== user.id) {\n        this.logger.warn('Email already in use by another account');\n        throw new BadRequestException('Email is not available');\n      }\n    }\n\n    const update: Updateable<UserTable> = {\n      email: dto.email,\n      name: dto.name,\n      avatarColor: dto.avatarColor,\n    };\n\n    if (dto.password) {\n      const hashedPassword = await this.cryptoRepository.hashBcrypt(dto.password, SALT_ROUNDS);\n      update.password = hashedPassword;\n      update.shouldChangePassword = false;\n    }\n\n    const updatedUser = await this.userRepository.update(user.id, update);\n\n    return mapUserAdmin(updatedUser);","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/immich-app/immich/blob/199723261c6ffa897fec8ccdaea6359e39c37cc3/server/src/services/user.service.ts#L43-L79","documentation":"A BadRequestException (HTTP 400) thrown by UserService.updateMe when the requested new email is already owned by a different user. The service looks up the email and, if a duplicate exists whose id differs from the acting user, rejects the change. This is a uniqueness guard for the self-service profile update path.","triggerScenarios":"PUT /users/me with an email that belongs to another account, including emails of soft-deleted users that still occupy the unique email column. Also triggered by case-variant collisions if the lookup is case-insensitive.","commonSituations":"User picks an email already registered; merging two accounts by renaming one to the other's email; an admin pre-reserved an email; a previously deleted user's email still in the table.","solutions":["Prompt the user to pick a different email and re-submit.","If the duplicate belongs to a soft-deleted account that should free the email, purge or hard-delete that account first.","Verify case sensitivity expectations; trim and normalize the email client-side before sending.","If the user believes the email is theirs, have an admin confirm ownership of the duplicate account before reassigning."],"exampleFix":"// before\nawait api.updateMe({ email: 'taken@example.com' }); // 400\n\n// after\nconst available = await api.checkEmailAvailable('taken@example.com');\nif (!available) {\n  showEmailTakenError();\n  return;\n}\nawait api.updateMe({ email: 'taken@example.com' });","handlingStrategy":"validation","validationCode":"async function isEmailAvailable(email) {\n  // call any email-availability or user-search endpoint the API exposes\n  const taken = await api.searchUsers({ email });\n  return !taken.some((u) => u.email.toLowerCase() === email.trim().toLowerCase());\n}\nif (!(await isEmailAvailable(newEmail))) { showEmailTaken(); return; }","typeGuard":"const isEmailNotAvailableError = (e: unknown): boolean =>\n  typeof e === 'object' && e !== null && (e as any).status === 400 && (e as any).message === 'Email is not available';","tryCatchPattern":"try {\n  await api.updateMe({ email: newEmail });\n} catch (e) {\n  if (isEmailNotAvailableError(e)) {\n    setFieldError('email', 'This email is already in use');\n    return;\n  }\n  throw e;\n}","preventionTips":["Normalize and trim the email client-side before submit.","Check availability before letting the user submit the form when an endpoint exists.","Show field-level errors for 400s so users can correct without a full retry."],"tags":["user","email","uniqueness","validation","nestjs"],"backgroundTag":null,"analyzedSha":"199723261c6ffa897fec8ccdaea6359e39c37cc3","analyzedAt":"2026-08-12T04:54:27.085Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}