{"record":{"id":"e9a403dab6708c42","repo":"fullstackhero/dotnet-starter-kit","slug":"role-not-found","errorCode":null,"errorMessage":"role not found","messagePattern":"role not found","errorType":"exception","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"src/Modules/Identity/Modules.Identity/Features/v1/Roles/RoleService.cs","lineNumber":100,"sourceCode":"            .Select(r => new RoleDto { Id = r.Id, Name = r.Name!, Description = r.Description })\n            .ToListAsync(cancellationToken)\n            .ConfigureAwait(false);\n\n        return new PagedResponse<RoleDto>\n        {\n            Items = rows,\n            PageNumber = page,\n            PageSize = size,\n            TotalCount = total,\n            TotalPages = (int)Math.Ceiling(total / (double)size),\n        };\n    }\n\n    public async Task<RoleDto?> GetRoleAsync(string id, CancellationToken cancellationToken = default)\n    {\n        FshRole? role = await roleManager.FindByIdAsync(id);\n\n        _ = role ?? throw new NotFoundException(\"role not found\");\n\n        return new RoleDto { Id = role.Id, Name = role.Name!, Description = role.Description };\n    }\n\n    public async Task<RoleDto> CreateOrUpdateRoleAsync(string roleId, string name, string description, CancellationToken cancellationToken = default)\n    {\n        FshRole? role = string.IsNullOrEmpty(roleId)\n            ? null\n            : await roleManager.FindByIdAsync(roleId);\n\n        if (role != null)\n        {\n            // System roles cannot be modified — neither renamed nor re-described.\n            EnsureNotSystemRole(role.Name, \"System roles cannot be modified.\");\n            // And no custom role can be renamed to a system role's name.\n            EnsureNotSystemRole(name, \"Cannot rename a role to a system role's name.\");\n\n            role.Name = name;","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Identity/Modules.Identity/Features/v1/Roles/RoleService.cs#L82-L118","documentation":"Generic sentinel thrown in RoleService when a role lookup by identifier fails. In the GetRoleAsync path it means FindByIdAsync returned no FshRole for the supplied id — the caller referenced a role that does not exist in this tenant's role store.","triggerScenarios":"Calling GetRoleAsync with an id that was deleted, a typo'd/truncated role id, or an id from a different tenant/database.","commonSituations":"Stale cached role ids in the frontend after a role was deleted; passing a permission or claim id instead of a role id; querying the wrong environment's database.","solutions":["Verify the role id exists (query AspNetRoles / roles list endpoint) before calling","Fix the source of the stale id — re-fetch the role list after deletions","Confirm you are connected to the correct database/tenant"],"exampleFix":"// before\nvar role = await roleService.GetRoleAsync(deletedId);\n// after\nvar roles = await roleService.ListAsync(ct);\nif (!roles.Any(r => r.Id == id)) return Results.NotFound();\nvar role = await roleService.GetRoleAsync(id, ct);","handlingStrategy":"try-catch","validationCode":"var exists = (await roleService.ListAllAsync(ct)).Any(r => r.Id == id);\nif (!exists) return Results.NotFound($\"Role {id} not found\");","typeGuard":"public static bool RoleExists(RoleDto? role) => role is not null && !string.IsNullOrEmpty(role.Id);","tryCatchPattern":"try { var role = await roleService.GetRoleAsync(id, ct); }\ncatch (NotFoundException ex) { return Results.NotFound(new { ex.Message, RoleId = id }); }","preventionTips":["Re-fetch role lists after any mutation instead of trusting cached ids","Treat role ids as opaque; never construct or parse them manually","Return 404 (not 500) when catching NotFoundException in endpoint maps"],"tags":["identity","roles","not-found"],"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"}