{"record":{"id":"33fe3fb293470e57","repo":"bitwarden/server","slug":"group-not-found-33fe3f","errorCode":null,"errorMessage":"Group not found.","messagePattern":"Group not found\\.","errorType":"exception","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"bitwarden_license/src/Scim/Groups/PutGroupCommand.cs","lineNumber":29,"sourceCode":"public class PutGroupCommand : IPutGroupCommand\n{\n    private readonly IGroupRepository _groupRepository;\n    private readonly IUpdateGroupCommand _updateGroupCommand;\n\n    public PutGroupCommand(\n        IGroupRepository groupRepository,\n        IUpdateGroupCommand updateGroupCommand)\n    {\n        _groupRepository = groupRepository;\n        _updateGroupCommand = updateGroupCommand;\n    }\n\n    public async Task<Group> PutGroupAsync(Organization organization, Guid id, ScimGroupRequestModel model)\n    {\n        var group = await _groupRepository.GetByIdAsync(id);\n        if (group == null || group.OrganizationId != organization.Id)\n        {\n            throw new NotFoundException(\"Group not found.\");\n        }\n\n        group.Name = model.DisplayName;\n        await _updateGroupCommand.UpdateGroupAsync(group, organization, EventSystemUser.SCIM);\n        await UpdateGroupMembersAsync(group, model);\n\n        return group;\n    }\n\n    private async Task UpdateGroupMembersAsync(Group group, ScimGroupRequestModel model)\n    {\n        if (model.Members == null)\n        {\n            return;\n        }\n\n        var memberIds = new List<Guid>();\n        foreach (var id in model.Members.Select(i => i.Value))","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/bitwarden_license/src/Scim/Groups/PutGroupCommand.cs#L11-L47","documentation":"Thrown as a NotFoundException (HTTP 404) by PutGroupCommand.PutGroupAsync when the group identified by {id} does not exist in the database or its OrganizationId does not match the {organization} parameter. PUT is a full-replace operation in SCIM 2.0, and this guard ensures the target resource is valid before overwriting it.","triggerScenarios":"PUT /v2/{organizationId}/Groups/{id} where the group GUID was deleted or belongs to a different org. The IdP sends a full group replacement for a resource it believes exists but was removed.","commonSituations":"Group deleted in Bitwarden but IdP still references it. Org mismatch from wrong SCIM API key. Race condition: group deleted between a GET and a PUT in the IdP sync cycle.","solutions":["Verify the group exists via GET /v2/{organizationId}/Groups/{id}.","If deleted, create a new group via POST and update the IdP reference.","Confirm the organizationId in the request matches the SCIM token's org.","Reconcile the IdP directory to remove stale group references."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"var existing = await scimClient.GetGroupAsync(orgId, groupId);\nif (existing == null) { /* reconcile — re-provision or clear IdP ref */ return; }\n// only then PUT","typeGuard":null,"tryCatchPattern":"try { await scimClient.PutGroupAsync(orgId, groupId, model); }\ncatch (ScimException ex) when (ex.StatusCode == 404)\n{ /* group gone — remove from IdP or re-create */ }","preventionTips":["Verify group existence before PUT.","Treat 404 on PUT as a signal to re-provision, not retry.","Reconcile IdP directory after any group deletions in Bitwarden."],"tags":["scim","not-found","groups","http-404","put"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}