bitwarden/server · error · NotFoundException
User not found.
Error message
User not found.
What it means
Thrown as a NotFoundException (HTTP 404) by the SCIM v2 UsersController Get action when the organization user details for {id} cannot be found or the retrieved user's OrganizationId does not match the route's {organizationId}. The SCIM exception filter returns a SCIM-formatted 404. This enforces tenant isolation and informs the IdP that the user resource no longer exists.
Source
Thrown at bitwarden_license/src/Scim/Controllers/v2/UsersController.cs:57
IRestoreOrganizationUserCommand restoreOrganizationUserCommand,
IRevokeOrganizationUserCommandV2 revokeOrganizationUserCommandV2)
{
_organizationUserRepository = organizationUserRepository;
_getUsersListQuery = getUsersListQuery;
_removeOrganizationUserCommand = removeOrganizationUserCommand;
_patchUserCommand = patchUserCommand;
_postUserCommand = postUserCommand;
_restoreOrganizationUserCommand = restoreOrganizationUserCommand;
_revokeOrganizationUserCommandV2 = revokeOrganizationUserCommandV2;
}
[HttpGet("{id}")]
public async Task<IActionResult> Get(Guid organizationId, Guid id)
{
var orgUser = await _organizationUserRepository.GetDetailsByIdAsync(id);
if (orgUser == null || orgUser.OrganizationId != organizationId)
{
throw new NotFoundException("User not found.");
}
return Ok(new ScimUserResponseModel(orgUser));
}
[HttpGet("")]
public async Task<IActionResult> Get(
Guid organizationId,
[FromQuery] GetUsersQueryParamModel model)
{
var usersListQueryResult = await _getUsersListQuery.GetUsersListAsync(organizationId, model);
var scimListResponseModel = new ScimListResponseModel<ScimUserResponseModel>
{
Resources = usersListQueryResult.userList.Select(u => new ScimUserResponseModel(u)).ToList(),
ItemsPerPage = model.Count,
TotalResults = usersListQueryResult.totalResults,
StartIndex = model.StartIndex,
};
return Ok(scimListResponseModel);View on GitHub (pinned to e93b962371)
Solutions
- List users via GET /v2/{organizationId}/Users to find the correct GUID for the user.
- If the user was removed, re-provision them via POST /v2/{organizationId}/Users.
- Verify the organizationId matches the SCIM bearer token's organization scope.
- Clear the IdP connector cache and re-sync to reconcile stale references.
Defensive patterns
Strategy: validation
Validate before calling
// Before GETting a specific user, verify the id is known
if (!await userExistsInIdpCache(userId))
{
logger.Warn("User {UserId} not in local cache; skipping GET", userId);
return null;
} Try / catch
try { var user = await scimClient.GetUserAsync(orgId, userId); }
catch (ScimException ex) when (ex.StatusCode == 404)
{ /* user removed — delete from IdP tracking or re-provision */ } Prevention
- Cache Bitwarden user GUIDs from list responses and purge entries that 404.
- Run periodic full-sync to reconcile IdP state with Bitwarden.
- Never retry a GET that 404s with the same id — it will not appear.
When it happens
Trigger: GET /v2/{organizationId}/Users/{id} where the organization user record was deleted, the user was revoked and purged, or the id belongs to a different organization. Occurs when an IdP queries for a user it cached but that has since been removed from Bitwarden.
Common situations: User was removed from the Bitwarden organization (or left the org) but the IdP still tracks them. Directory sync sent a GET for a user GUID that was never provisioned. Cross-tenant id confusion from misconfigured SCIM API keys.
Related errors
- User not found.
- Group not found.
- ExternalId cannot exceed 300 characters.
- ExternalId already exists for another user.
- result.AsError.Message
AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13).
Data as JSON: /api/errors/e786f87d8c2a0aa7.
Report an issue: GitHub.