{"record":{"id":"cfa97dc4ab0bba06","repo":"bitwarden/server","slug":"conflict","errorCode":null,"errorMessage":"Conflict.","messagePattern":"Conflict\\.","errorType":"exception","errorClass":"ConflictException","httpStatus":409,"severity":"error","filePath":"bitwarden_license/src/Scim/Groups/PostGroupCommand.cs","lineNumber":34,"sourceCode":"    public PostGroupCommand(\n        IGroupRepository groupRepository,\n        ICreateGroupCommand createGroupCommand)\n    {\n        _groupRepository = groupRepository;\n        _createGroupCommand = createGroupCommand;\n    }\n\n    public async Task<Group> PostGroupAsync(Organization organization, ScimGroupRequestModel model)\n    {\n        if (string.IsNullOrWhiteSpace(model.DisplayName))\n        {\n            throw new BadRequestException();\n        }\n\n        var groups = await _groupRepository.GetManyByOrganizationIdAsync(organization.Id);\n        if (!string.IsNullOrWhiteSpace(model.ExternalId) && groups.Any(g => g.ExternalId == model.ExternalId))\n        {\n            throw new ConflictException();\n        }\n\n        var group = model.ToGroup(organization.Id);\n        await _createGroupCommand.CreateGroupAsync(group, organization, EventSystemUser.SCIM, collections: null);\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":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/bitwarden_license/src/Scim/Groups/PostGroupCommand.cs#L16-L52","documentation":"Thrown as a ConflictException (HTTP 409) with the default message 'Conflict.' by PostGroupCommand.PostGroupAsync when creating a group whose externalId already matches an existing group in the same organization. Unlike the patch path, this uses exact string comparison (==) rather than case-insensitive. The default ConflictException constructor supplies the message 'Conflict.'.","triggerScenarios":"POST /v2/{organizationId}/Groups with a non-empty externalId that matches an existing group's externalId in the same org. Common when the IdP retries a creation that partially succeeded, or when two groups in the directory share the same externalId.","commonSituations":"IdP re-provisioning after a timeout where the first POST succeeded but the response was lost. Duplicate externalIds in the source directory. Directory connector re-sync without deduplication.","solutions":["Check if the group already exists: GET /v2/{organizationId}/Groups?filter=externalId eq \"...\".","If it exists, use PUT or PATCH to update it instead of POSTing a new one.","Deduplicate externalIds in the source directory before provisioning.","Configure the IdP to treat 409 as 'already exists' and reconcile rather than retry-create."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before creating, check if a group with this externalId exists\nvar existing = await scimClient.ListGroupsAsync(orgId, filter: $\"externalId eq \\\"{externalId}\\\"\");\nif (existing.Any()) { /* use PUT/PATCH on existing instead */ }","typeGuard":null,"tryCatchPattern":"try { await scimClient.CreateGroupAsync(orgId, model); }\ncatch (ScimException ex) when (ex.StatusCode == 409)\n{ // group likely exists already — fetch and update instead\n  var existing = await scimClient.ListGroupsAsync(orgId, filter: $\"externalId eq \\\"{model.ExternalId}\\\"\");\n  if (existing.Any()) await scimClient.PutGroupAsync(orgId, existing.First().Id, model); }","preventionTips":["Implement idempotent SCIM creation: on 409, fall back to lookup-and-update.","Deduplicate externalIds in the source directory.","Avoid retrying POST on 409 — switch to PUT/PATCH."],"tags":["scim","conflict","groups","http-409","externalid","uniqueness","create"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}