fullstackhero/dotnet-starter-kit · error · CustomException
Tenant must have at least one active administrator.
Error message
Tenant must have at least one active administrator.
What it means
UserStatusService.EnsureMinimumActiveAdminsAsync throws CustomException with 400 BadRequest ("Tenant must have at least one active administrator.") when deactivating the target would leave the tenant with zero active admin users. It fetches all users in the Admin role and verifies at least one remains IsActive; audited as NoActiveAdmins first.
Solutions
- Activate another user and grant them the Admin role before deactivating this one.
- Reactivate an existing inactive admin first.
- Skip the last active admin in bulk deactivation jobs.
- Keep at least two active admins per tenant as an operational rule.
Example fix
// before
await mediator.Send(new ToggleUserStatusCommand { UserId = lastAdminId, ActivateUser = false });
// after
var newAdmin = await userManager.FindByEmailAsync("ops@tenant.com");
await userManager.AddToRoleAsync(newAdmin, RoleConstants.Admin);
await mediator.Send(new ToggleUserStatusCommand { UserId = lastAdminId, ActivateUser = false }); Defensive patterns
Strategy: validation
Validate before calling
var admins = await userManager.GetUsersInRoleAsync(RoleConstants.Admin);
if (!admins.Any(u => u.IsActive && u.Id != targetId))
return Result.BadRequest("Promote another active admin first."); Try / catch
try { ... }
catch (CustomException) { showBanner("Tenant needs at least one active administrator."); } Prevention
- Maintain redundancy: at least two active admins per tenant.
- Pre-check the remaining-admin count in deactivation workflows.
- Monitor tenant admin counts with a recurring job/report.
- Handle the error gracefully in bulk operations by skipping the last admin.
When it happens
Trigger: Deactivating the last remaining active administrator of a tenant, i.e. after this change no user in the Admin role would remain IsActive.
Common situations: Tenants where other admins are already inactive or their Admin role was stripped; bulk deactivation jobs that would drain all admins; freshly created tenants with a single seeded admin.
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
- Administrators cannot be deactivated.
- Users cannot deactivate themselves.
- not allowed to change this file's visibility
- Group with ID ' ' not found.
- Users not found
AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15).
Data as JSON: /api/errors/73a720ef3493c4d7.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Identity/Modules.Identity/Services/UserStatusService.cs:110
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);
}
}
private static void ApplyStatusChange(ToggleStatusContext context)
{
if (context.ActivateUser)
{
context.TargetUser.Activate(context.ActorId.ToString(), context.TenantId);
}
else
{
context.TargetUser.Deactivate(context.ActorId.ToString(), "Status toggled by administrator", context.TenantId);
}
}
private async Task SaveAndAuditAsync(
ToggleStatusContext context,
CancellationToken cancellationToken)View on GitHub (pinned to 3f2959e683)