fullstackhero/dotnet-starter-kit · warning · CustomException

Administrators cannot be deactivated.

Error message

Administrators cannot be deactivated.

What it means

UserStatusService.ValidateTogglePermissionsAsync throws CustomException with 400 BadRequest ("Administrators cannot be deactivated.") when the target user holds the Admin role and deactivation was requested. The failure is audited as AdminDeactivationBlocked before throwing.

Solutions

  1. Remove the Admin role from the target first, then deactivate.
  2. Skip admin-role users in bulk deactivation jobs.
  3. Deactivate a different, non-admin account instead.
  4. If an admin must lose access, revoke their roles/logins rather than deactivating.

Example fix

// before
await mediator.Send(new ToggleUserStatusCommand { UserId = adminUserId, ActivateUser = false });
// after
if (!await userManager.IsInRoleAsync(targetUser, RoleConstants.Admin))
    await mediator.Send(new ToggleUserStatusCommand { UserId = adminUserId, ActivateUser = false });
Defensive patterns

Strategy: validation

Validate before calling

var targetIsAdmin = await userManager.IsInRoleAsync(targetUser, RoleConstants.Admin);
if (targetIsAdmin && !command.ActivateUser)
    return Result.BadRequest("Admin accounts cannot be deactivated.");

Try / catch

try { ... }
catch (CustomException) { showBanner("Target is an administrator and cannot be deactivated."); }

Prevention

When it happens

Trigger: Toggling activateUser=false for any user currently in the Admin role, regardless of whether the actor is also an admin.

Common situations: Bulk user-management scripts deactivating all inactive users including admins; operators deactivating a colleague who is an admin; seeded admin accounts included in cleanup jobs.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15). Data as JSON: /api/errors/ce0b9ce721a32d95. Report an issue: GitHub.

Appendix: source

Thrown at src/Modules/Identity/Modules.Identity/Services/UserStatusService.cs:93

        ToggleStatusContext context,
        CancellationToken cancellationToken)
    {
        if (!await userManager.IsInRoleAsync(context.Actor, RoleConstants.Admin))
        {
            await AuditPolicyFailureAsync(context, "ActorNotAdmin", cancellationToken);
            throw new ForbiddenException("Only administrators can change user status.");
        }

        if (!context.ActivateUser && context.ActorId.ToString() == context.TargetUser.Id)
        {
            await AuditPolicyFailureAsync(context, "SelfDeactivationBlocked", cancellationToken);
            throw new CustomException("Users cannot deactivate themselves.", Array.Empty<string>(), HttpStatusCode.BadRequest);
        }

        if (!context.ActivateUser && await userManager.IsInRoleAsync(context.TargetUser, RoleConstants.Admin))
        {
            await AuditPolicyFailureAsync(context, "AdminDeactivationBlocked", cancellationToken);
            throw new CustomException("Administrators cannot be deactivated.", Array.Empty<string>(), HttpStatusCode.BadRequest);
        }

        if (!context.ActivateUser)
        {
            await EnsureMinimumActiveAdminsAsync(context, cancellationToken);
        }
    }

    private async Task EnsureMinimumActiveAdminsAsync(
        ToggleStatusContext context,
        CancellationToken cancellationToken)
    {
        var activeAdmins = await userManager.GetUsersInRoleAsync(RoleConstants.Admin);
        if (!activeAdmins.Any(u => u.IsActive))
        {
            await AuditPolicyFailureAsync(context, "NoActiveAdmins", cancellationToken);
            throw new CustomException("Tenant must have at least one active administrator.", Array.Empty<string>(), HttpStatusCode.BadRequest);
        }

View on GitHub (pinned to 3f2959e683)