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
- Remove the Admin role from the target first, then deactivate.
- Skip admin-role users in bulk deactivation jobs.
- Deactivate a different, non-admin account instead.
- 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
- Load target roles before listing users for deactivation.
- Exclude admin-role users from deactivation UI/actions.
- Document that role removal is the path to retiring admin access.
- Pre-check targets in bulk scripts.
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
- Users cannot deactivate themselves.
- Tenant must have at least one active administrator.
- Toggle status failed
- A category cannot be its own parent.
- Setting this parent would create a cycle.
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)