bitwarden/server · error · NotFoundException

User not found.

Error message

User not found.

What it means

Thrown as a NotFoundException (HTTP 404) by PatchUserCommand.PatchUserAsync when the organization user for {id} does not exist or its OrganizationId does not match the route's organizationId. This is the initial existence check before processing any PATCH operations on the user.

Source

Thrown at bitwarden_license/src/Scim/Users/PatchUserCommand.cs:35

    private readonly IRevokeOrganizationUserCommand _revokeOrganizationUserCommand;

    public PatchUserCommand(IOrganizationUserRepository organizationUserRepository,
        IRestoreOrganizationUserCommand restoreOrganizationUserCommand,
        ILogger<PatchUserCommand> logger,
        IRevokeOrganizationUserCommand revokeOrganizationUserCommand)
    {
        _organizationUserRepository = organizationUserRepository;
        _restoreOrganizationUserCommand = restoreOrganizationUserCommand;
        _logger = logger;
        _revokeOrganizationUserCommand = revokeOrganizationUserCommand;
    }

    public async Task PatchUserAsync(Guid organizationId, Guid id, ScimPatchModel model)
    {
        var orgUser = await _organizationUserRepository.GetByIdAsync(id);
        if (orgUser == null || orgUser.OrganizationId != organizationId)
        {
            throw new NotFoundException("User not found.");
        }

        var operationHandled = false;
        foreach (var operation in model.Operations)
        {
            // Replace operations
            if (operation.Op?.ToLowerInvariant() == PatchOps.Replace)
            {
                // Active from path
                if (operation.Path?.ToLowerInvariant() == "active")
                {
                    var active = operation.Value.ToString()?.ToLowerInvariant();
                    var handled = await HandleActiveOperationAsync(orgUser, active == "true");
                    if (!operationHandled)
                    {
                        operationHandled = handled;
                    }
                    // Re-fetch to pick up status changes persisted by restore/revoke

View on GitHub (pinned to e93b962371)

Solutions

  1. List users via GET /v2/{organizationId}/Users to confirm whether the user still exists.
  2. If removed, re-provision via POST or remove the stale reference from the IdP.
  3. Verify the organizationId matches the SCIM token's organization scope.
  4. Re-sync the IdP directory to reconcile.
Defensive patterns

Strategy: validation

Validate before calling

var existing = await scimClient.GetUserAsync(orgId, userId);
if (existing == null) { /* user gone — reconcile IdP ref */ return; }
// only then PATCH

Try / catch

try { await scimClient.PatchUserAsync(orgId, userId, patchModel); }
catch (ScimException ex) when (ex.StatusCode == 404)
{ /* user removed — delete from IdP or re-provision */ }

Prevention

When it happens

Trigger: PATCH /v2/{organizationId}/Users/{id} where the organization user was deleted, revoked and purged, or belongs to a different org. IdP sends an update (e.g., deactivate) for a user no longer in Bitwarden.

Common situations: User removed from Bitwarden but IdP still tracks them. IdP sends a deactivation PATCH after the user was already deleted. Cross-tenant GUID confusion from wrong SCIM key.

Related errors


AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13). Data as JSON: /api/errors/87193588d1745e85. Report an issue: GitHub.