{"record":{"id":"608235af9de3b112","repo":"fullstackhero/dotnet-starter-kit","slug":"users-not-found-string-join-invaliduserids","errorCode":null,"errorMessage":"Users not found: {string.Join(\", \", invalidUserIds)}","messagePattern":"Users not found: (.+?)","errorType":"exception","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"src/Modules/Identity/Modules.Identity/Features/v1/Groups/AddUsersToGroup/AddUsersToGroupCommandHandler.cs","lineNumber":47,"sourceCode":"        // Validate group exists\n        var groupExists = await _dbContext.Groups\n            .AnyAsync(g => g.Id == command.GroupId, cancellationToken);\n\n        if (!groupExists)\n        {\n            throw new NotFoundException($\"Group with ID '{command.GroupId}' not found.\");\n        }\n\n        // Validate user IDs exist\n        var existingUserIds = await _dbContext.Users\n            .Where(u => command.UserIds.Contains(u.Id))\n            .Select(u => u.Id)\n            .ToListAsync(cancellationToken);\n\n        var invalidUserIds = command.UserIds.Except(existingUserIds).ToList();\n        if (invalidUserIds.Count > 0)\n        {\n            throw new NotFoundException($\"Users not found: {string.Join(\", \", invalidUserIds)}\");\n        }\n\n        // Get existing memberships\n        var existingMemberships = await _dbContext.UserGroups\n            .Where(ug => ug.GroupId == command.GroupId && command.UserIds.Contains(ug.UserId))\n            .Select(ug => ug.UserId)\n            .ToListAsync(cancellationToken);\n\n        var alreadyMemberUserIds = existingMemberships.ToList();\n        var usersToAdd = command.UserIds.Except(existingMemberships).ToList();\n\n        // Add new memberships\n        var currentUserId = _currentUser.GetUserId().ToString();\n        foreach (var userId in usersToAdd)\n        {\n            _dbContext.UserGroups.Add(UserGroup.Create(userId, command.GroupId, currentUserId));\n        }\n","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Identity/Modules.Identity/Features/v1/Groups/AddUsersToGroup/AddUsersToGroupCommandHandler.cs#L29-L65","documentation":"After confirming the group exists, the handler intersects command.UserIds with existing user ids and throws NotFoundException naming every missing user. All-or-nothing: no users are added if any id is invalid.","triggerScenarios":"AddUsersToGroup call where one or more UserIds do not exist in the tenant — deleted users, users from another tenant, or malformed GUIDs.","commonSituations":"Batching users from an old export after users were deleted; mixing ids across dev/staging databases; sending usernames instead of user ids.","solutions":["Resolve user ids via the users list endpoint in the same tenant before calling","Remove the invalid ids reported in the message and retry with the valid subset","Recreate missing users if the deletion was accidental"],"exampleFix":"// before\nuserIds: [\"3f2...\", \"00000000-0000-0000-0000-000000000000\"]\n// after\nvar valid = users.Where(u => u.TenantId == tenant).Select(u => u.Id); // only existing ids","handlingStrategy":"validation","validationCode":"var tenantUserIds = (await api.ListUsers()).Select(u => u.Id).ToHashSet();\nvar invalid = userIds.Where(id => !tenantUserIds.Contains(id)).ToList();","typeGuard":"static bool AllValid(IEnumerable<string> ids, ISet<string> known) => ids.All(known.Contains);","tryCatchPattern":null,"preventionTips":["Resolve users by id against the current tenant before batch operations","Drop deleted users from stored user lists","Validate GUID format before sending"],"tags":["http-404","identity","users","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"}