fullstackhero/dotnet-starter-kit · error · NotFoundException

Group with ID ' ' not found.

Error message

Group with ID '{command.Id}' not found.

What it means

Thrown by DeleteGroupCommandHandler when no group with the provided command.Id exists in the tenant-scoped Groups set. This is a not-found guard before deletion: the lookup (optionally with member/role cleanup) found no matching aggregate, so the delete cannot proceed.

Solutions

  1. Re-fetch the group list and confirm the id before deleting
  2. Treat 404 on delete as success for idempotent cleanup logic
  3. Fix tenant context/headers if the id exists but under a different tenant

Example fix

// before
await api.DeleteGroup(id); // may 404 on retry
// after
try { await api.DeleteGroup(id); } catch (ApiException e) when (e.Status == 404) { /* already gone */ }
Defensive patterns

Strategy: try-catch

Validate before calling

var exists = (await api.SearchGroups(name)).Any(g => g.Id == id);
if (!exists) return; // nothing to delete

Try / catch

try { await api.DeleteGroup(id); }
catch (ApiException e) when (e.Status == 404) { /* idempotent: already deleted */ }

Prevention

When it happens

Trigger: DELETE /groups/{id} for an already-deleted group, a nonexistent id, a cross-tenant id, or Guid.Empty.

Common situations: Double delete from a retrying client; stale list data after another admin deleted the group; hardcoded ids in scripts.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

Thrown at src/Modules/Identity/Modules.Identity/Features/v1/Groups/DeleteGroup/DeleteGroupCommandHandler.cs:30

{
    private readonly IdentityDbContext _dbContext;
    private readonly ICurrentUser _currentUser;
    private readonly IUserPermissionService _userPermissionService;

    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);

View on GitHub (pinned to 3f2959e683)