immich-app/immich · error · BadRequestException

Email is not available

Error message

Email is not available

What it means

Thrown by UserAdminService.update when the requested new email is already used by a different account. Uniqueness of emails is enforced per instance; the check excludes the target user itself (duplicate.id !== id). It is a 400 BadRequest for a uniqueness conflict.

Solutions

  1. Choose a different email or free up the address by updating/removing the conflicting account first
  2. Check availability with a user lookup by email before submitting the update
  3. If the duplicate account is stale, delete it, then retry the email change

Example fix

// before
await adminApi.updateUser(userId, { email: 'shared@corp.com' });
// after
const existing = await adminApi.getUserByEmail('shared@corp.com');
if (existing && existing.id !== userId) throw new Error('email taken');
await adminApi.updateUser(userId, { email: 'shared@corp.com' });
Defensive patterns

Strategy: validation

Validate before calling

const existing = await adminApi.getUserByEmail(dto.email);
if (existing && existing.id !== id) {
  throw new Error(`email ${dto.email} is already in use`);
}

Try / catch

try { await adminApi.updateUser(id, dto); } catch (e) {
  if (e.response?.status === 400 && /Email is not available/.test(e.response?.data?.message ?? '')) {
    // prompt for a different email or resolve the conflicting account
  }
  throw e;
}

Prevention

When it happens

Trigger: PUT/PATCH /api/admin/users/:id with dto.email equal to the email of another existing user. Also triggered by case/format variants that resolve to an existing account, or re-inviting a user whose email was taken by a deleted-but-restored account.

Common situations: Merging accounts or changing a user's email to one already registered; renaming a user to a former employee's address that still exists; duplicate registrations before the update attempt.

Related errors


AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15). Data as JSON: /api/errors/a64d9f36ea2843c7. Report an issue: GitHub.

Appendix: source

Thrown at server/src/services/user-admin.service.ts:71

    return mapUserAdmin(user);
  }

  async update(auth: AuthDto, id: string, dto: UserAdminUpdateDto): Promise<UserAdminResponseDto> {
    const user = await this.findOrFail(id, {});

    if (dto.isAdmin !== undefined && dto.isAdmin !== auth.user.isAdmin && auth.user.id === id) {
      throw new BadRequestException('Admin status can only be changed by another admin');
    }

    if (dto.quotaSizeInBytes && user.quotaSizeInBytes !== dto.quotaSizeInBytes) {
      await this.userRepository.syncUsage(id);
    }

    if (dto.email) {
      const duplicate = await this.userRepository.getByEmail(dto.email);
      if (duplicate && duplicate.id !== id) {
        this.logger.debug('Email already in use by another account');
        throw new BadRequestException('Email is not available');
      }
    }

    if (dto.storageLabel) {
      const duplicate = await this.userRepository.getByStorageLabel(dto.storageLabel);
      if (duplicate && duplicate.id !== id) {
        throw new BadRequestException('Storage label already in use by another account');
      }
    }

    if (dto.password) {
      dto.password = await this.cryptoRepository.hashBcrypt(dto.password, SALT_ROUNDS);
    }

    if (dto.pinCode) {
      dto.pinCode = await this.cryptoRepository.hashBcrypt(dto.pinCode, SALT_ROUNDS);
    }

View on GitHub (pinned to e55ac299a4)