{"record":{"id":"ee492c8b28e9eede","repo":"fullstackhero/dotnet-starter-kit","slug":"roles-not-found-string-join-invalidroleids","errorCode":null,"errorMessage":"Roles not found: {string.Join(\", \", invalidRoleIds)}","messagePattern":"Roles not found: (.+?)","errorType":"exception","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"src/Modules/Identity/Modules.Identity/Features/v1/Groups/CreateGroup/CreateGroupCommandHandler.cs","lineNumber":49,"sourceCode":"        if (nameExists)\n        {\n            throw new CustomException($\"Group with name '{command.Name}' already exists.\", (IEnumerable<string>?)null, System.Net.HttpStatusCode.Conflict);\n        }\n\n        // Validate role IDs exist — fetch Id+Name in a single query to avoid a second roundtrip later\n        List<(string Id, string Name)> resolvedRoles = [];\n        if (command.RoleIds is { Count: > 0 })\n        {\n            var rawRoles = await _dbContext.Roles\n                .Where(r => command.RoleIds.Contains(r.Id))\n                .Select(r => new { r.Id, r.Name })\n                .ToListAsync(cancellationToken);\n            resolvedRoles = rawRoles.Select(r => (r.Id, r.Name!)).ToList();\n\n            var invalidRoleIds = command.RoleIds.Except(resolvedRoles.Select(r => r.Id)).ToList();\n            if (invalidRoleIds.Count > 0)\n            {\n                throw new NotFoundException($\"Roles not found: {string.Join(\", \", invalidRoleIds)}\");\n            }\n        }\n\n        var group = Group.Create(\n            name: command.Name,\n            description: command.Description,\n            isDefault: command.IsDefault,\n            isSystemGroup: false,\n            createdBy: _currentUser.GetUserId().ToString());\n\n        // Add role assignments\n        foreach (var role in resolvedRoles)\n        {\n            _dbContext.GroupRoles.Add(GroupRole.Create(group.Id, role.Item1));\n        }\n\n        _dbContext.Groups.Add(group);\n        await _dbContext.SaveChangesAsync(cancellationToken);","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Identity/Modules.Identity/Features/v1/Groups/CreateGroup/CreateGroupCommandHandler.cs#L31-L67","documentation":"Thrown during group creation when one or more role IDs supplied in command.RoleIds do not match any role in the identity store; the handler pre-fetches Id+Name for the requested IDs and this exception fires for the subset that resolved to nothing (invalidRoleIds). It signals bad client input (stale or nonexistent role references), not a server failure.","triggerScenarios":"CreateGroup with RoleIds containing deleted role ids, roles from another tenant, or malformed/empty GUID strings.","commonSituations":"Role removed by an admin between UI load and submit; copying RoleIds from another environment; stale permission catalogs on the client.","solutions":["Refresh the role list from GET /roles in the same tenant and resubmit with valid ids","Drop the invalid role ids from the payload and create the group without them","Recreate deleted roles if they are still required"],"exampleFix":"// before\nroleIds: staleRoleIds // may include deleted roles\n// after\nvar roles = await api.GetRoles();\nroleIds: staleRoleIds.Where(id => roles.Any(r => r.Id == id)).ToList();","handlingStrategy":"validation","validationCode":"var roleIds = (await api.ListRoles()).Select(r => r.Id).ToHashSet();\nvar invalid = cmd.RoleIds.Where(id => !roleIds.Contains(id)).ToList();","typeGuard":"static bool RolesResolve(IEnumerable<string> ids, ISet<string> known) => ids.All(known.Contains);","tryCatchPattern":null,"preventionTips":["Refresh the role list right before submitting role-bearing payloads","Re-fetch roles after any role deletion","Don't copy RoleIds between environments"],"tags":["http-404","identity","roles","batch-validation"],"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"}