fullstackhero/dotnet-starter-kit · error · ForbiddenException
System groups cannot be deleted.
Error message
System groups cannot be deleted.
What it means
DeleteGroup refuses to delete groups flagged IsSystemGroup, throwing ForbiddenException (HTTP 403). System groups are infrastructure-owned (seeded by migrations/platform code) and must not be removed by API callers.
Solutions
- Filter out IsSystemGroup groups before issuing deletes
- Hide system groups from destructive UI actions
- Catch 403 and skip the group in bulk operations
Example fix
// before foreach (var g in allGroups) await api.DeleteGroup(g.Id); // after foreach (var g in allGroups.Where(g => !g.IsSystemGroup)) await api.DeleteGroup(g.Id);
Defensive patterns
Strategy: validation
Validate before calling
var group = await api.GetGroupByIdSafe(id); if (group?.IsSystemGroup == true) skip delete;
Type guard
bool Deletable(GroupDto g) => !g.IsSystemGroup;
Try / catch
try { await api.DeleteGroup(id); }
catch (ApiException e) when (e.Status == 403) { logger.LogInformation("Group {Id} is a system group; skipped", id); } Prevention
- Filter IsSystemGroup out of bulk delete targets
- Hide delete actions for system groups in UI
- Never attempt to 'reset' built-in groups via delete
When it happens
Trigger: DELETE /groups/{id} where the target group has IsSystemGroup = true (e.g. built-in seeded groups).
Common situations: Bulk cleanup scripts iterating all groups including system ones; admin UI not hiding system groups; trying to 'reset' a tenant by deleting its built-in groups.
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
- Users cannot be removed from a default group.
- System groups cannot be modified.
- Only administrators can change user status.
- Only channel admins can add members to private channels.
- Channel admin role required.
AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15).
Data as JSON: /api/errors/4612ded8414c667e.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Identity/Modules.Identity/Features/v1/Groups/DeleteGroup/DeleteGroupCommandHandler.cs:34
public DeleteGroupCommandHandler(IdentityDbContext dbContext, ICurrentUser currentUser, IUserPermissionService userPermissionService)
{
_dbContext = dbContext;
_currentUser = currentUser;
_userPermissionService = userPermissionService;
}
public async ValueTask<Unit> Handle(DeleteGroupCommand command, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(command);
var group = await _dbContext.Groups
.FirstOrDefaultAsync(g => g.Id == command.Id, cancellationToken)
?? throw new NotFoundException($"Group with ID '{command.Id}' not found.");
if (group.IsSystemGroup)
{
throw new ForbiddenException("System groups cannot be deleted.");
}
// Snapshot members before delete; soft-delete flips IsDeleted but membership rows
// persist, so capture first for clarity.
var memberIds = await _dbContext.UserGroups
.Where(ug => ug.GroupId == command.Id)
.Select(ug => ug.UserId)
.ToListAsync(cancellationToken);
// Soft delete via domain method
group.Delete(_currentUser.GetUserId().ToString());
await _dbContext.SaveChangesAsync(cancellationToken);
// A deleted group can no longer contribute its roles to members' effective
// permission sets — flush each member's cached entry.
foreach (var userId in memberIds)
{View on GitHub (pinned to 3f2959e683)