{"record":{"id":"f8916b6f93303623","repo":"fullstackhero/dotnet-starter-kit","slug":"group-with-id-query-id-not-found","errorCode":null,"errorMessage":"Group with ID '{query.Id}' not found.","messagePattern":"Group with ID '(.+?)' not found\\.","errorType":"exception","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"src/Modules/Identity/Modules.Identity/Features/v1/Groups/GetGroupById/GetGroupByIdQueryHandler.cs","lineNumber":25,"sourceCode":"\nnamespace FSH.Modules.Identity.Features.v1.Groups.GetGroupById;\n\npublic sealed class GetGroupByIdQueryHandler : IQueryHandler<GetGroupByIdQuery, GroupDto>\n{\n    private readonly IdentityDbContext _dbContext;\n\n    public GetGroupByIdQueryHandler(IdentityDbContext dbContext)\n    {\n        _dbContext = dbContext;\n    }\n\n    public async ValueTask<GroupDto> Handle(GetGroupByIdQuery query, CancellationToken cancellationToken)\n    {\n        var group = await _dbContext.Groups\n            .AsNoTracking()\n            .Include(g => g.GroupRoles)\n            .FirstOrDefaultAsync(g => g.Id == query.Id, cancellationToken)\n            ?? throw new NotFoundException($\"Group with ID '{query.Id}' not found.\");\n\n        var memberCount = await _dbContext.UserGroups\n            .AsNoTracking()\n            .CountAsync(ug => ug.GroupId == group.Id, cancellationToken);\n\n        var roleIds = group.GroupRoles.Select(gr => gr.RoleId).ToList();\n        var roleNames = roleIds.Count > 0\n            ? await _dbContext.Roles\n                .AsNoTracking()\n                .Where(r => roleIds.Contains(r.Id))\n                .Select(r => r.Name!)\n                .ToListAsync(cancellationToken)\n            : [];\n\n        return new GroupDto\n        {\n            Id = group.Id,\n            Name = group.Name,","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Identity/Modules.Identity/Features/v1/Groups/GetGroupById/GetGroupByIdQueryHandler.cs#L7-L43","documentation":"Thrown by GetGroupByIdQueryHandler when the no-tracking query (including GroupRoles) for query.Id returns null. It means no group with that ID exists (or is invisible under the tenant filter), so the read model cannot be built.","triggerScenarios":"GET /groups/{id} with a nonexistent, deleted, cross-tenant, or malformed id.","commonSituations":"Bookmark/deep-link to a deleted group; stale client cache after deletion; unit tests reusing random Guids.","solutions":["Verify the id exists via the groups list endpoint","Handle 404 in the UI by navigating back / showing 'group not found'","Re-check tenant headers if the group exists in another tenant"],"exampleFix":"// before\nvar group = await api.GetGroupById(routeId); // crashes on 404\n// after\ntry { var group = await api.GetGroupById(routeId); }\ncatch (ApiException e) when (e.Status == 404) { navigate('/groups'); }","handlingStrategy":"try-catch","validationCode":"const guidRe = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nif (!guidRe.test(routeId)) navigate('/groups');","typeGuard":"const isValidGroupId = (v: string | undefined): v is string => !!v && guidRe.test(v);","tryCatchPattern":"try { return await api.GetGroupById(id); }\ncatch (e) { if (is404(e)) { showNotFound(); return null; } throw e; }","preventionTips":["Invalidate cached group detail after deletion","Handle deep links to deleted groups gracefully","Validate route params before fetching"],"tags":["http-404","identity","groups","query"],"backgroundTag":"entity-not-found","analyzedSha":"3f2959e683e9f83f13e55e1678c9119f63c7e8e5","analyzedAt":"2026-09-15T22:20:53.684Z","contentChangedAt":"2026-09-15T22:20:53.684Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}