immich-app/immich · error · ForbiddenException

Cannot delete your own account

Error message

Cannot delete your own account

What it means

Thrown by UserAdminService.delete when an admin attempts to delete their own account. Self-deletion is forbidden (403 ForbiddenException) to avoid orphaning the instance's last admin and breaking session state. Deletion must be performed by a different admin.

Solutions

  1. Have another admin perform the deletion
  2. Promote a second user to admin, then delete the original account with that account
  3. Skip the caller's own ID in bulk-delete scripts (filter out auth.user.id)

Example fix

// before
for (const id of userIds) await adminApi.deleteUser(id, { force: false });
// after
for (const id of userIds.filter(u => u !== myUserId)) await adminApi.deleteUser(id, { force: false });
Defensive patterns

Strategy: validation

Validate before calling

if (id === auth.user.id) {
  throw new Error('cannot delete your own account; use another admin');
}

Try / catch

try { await adminApi.deleteUser(id, dto); } catch (e) {
  if (e.response?.status === 403 && /your own account/.test(e.response?.data?.message ?? '')) {
    // skip this id in bulk flows; require another admin session
  }
  throw e;
}

Prevention

When it happens

Trigger: DELETE /api/admin/users/:id where id === auth.user.id, regardless of the force flag. findOrFail succeeds, then the identity comparison throws.

Common situations: Cleaning up user lists with a script that includes the caller's own ID; an admin testing the delete endpoint on themselves; single-admin instances where the only admin tries to remove their account.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

Appendix: source

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

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

    if (dto.storageLabel === '') {
      dto.storageLabel = null;
    }

    const updatedUser = await this.userRepository.update(id, { ...dto, updatedAt: new Date() });

    return mapUserAdmin(updatedUser);
  }

  async delete(auth: AuthDto, id: string, dto: UserAdminDeleteDto): Promise<UserAdminResponseDto> {
    const { force } = dto;
    await this.findOrFail(id, {});
    if (auth.user.id === id) {
      throw new ForbiddenException('Cannot delete your own account');
    }

    await this.albumRepository.softDeleteAll(id);

    const status = force ? UserStatus.Removing : UserStatus.Deleted;
    const user = await this.userRepository.update(id, { status, deletedAt: new Date() });

    await this.eventRepository.emit('UserTrash', user);

    if (force) {
      await this.jobRepository.queue({ name: JobName.UserDelete, data: { id: user.id, force } });
    }

    return mapUserAdmin(user);
  }

  async restore(auth: AuthDto, id: string): Promise<UserAdminResponseDto> {
    await this.findOrFail(id, { withDeleted: true });

View on GitHub (pinned to e55ac299a4)