bitwarden/server · warning · BadRequestException

Already accepted.

Error message

Already accepted.

What it means

Thrown inside AcceptUserAsync when the ProviderUser's Status is not Invited — the user already accepted or was confirmed. Acceptance is a one-time state transition. BadRequestException (HTTP 400).

Source

Thrown at bitwarden_license/src/Commercial.Core/AdminConsole/Services/ProviderService.cs:255

            await SendInviteAsync(providerUser, provider);
            result.Add(Tuple.Create(providerUser, ""));
        }

        return result;
    }

    public async Task<ProviderUser> AcceptUserAsync(Guid providerUserId, User user, string token)
    {
        var providerUser = await _providerUserRepository.GetByIdAsync(providerUserId);
        if (providerUser == null)
        {
            throw new BadRequestException("User invalid.");
        }

        if (providerUser.Status != ProviderUserStatusType.Invited)
        {
            throw new BadRequestException("Already accepted.");
        }

        if (!CoreHelpers.TokenIsValid("ProviderUserInvite", _dataProtector, token, user.Email, providerUser.Id,
            _globalSettings.OrganizationInviteExpirationHours))
        {
            throw new BadRequestException("Invalid token.");
        }

        if (string.IsNullOrWhiteSpace(providerUser.Email) ||
            !providerUser.Email.Equals(user.Email, StringComparison.InvariantCultureIgnoreCase))
        {
            throw new BadRequestException("User email does not match invite.");
        }

        var organizationAutoConfirmPolicyRequirement = await _policyRequirementQuery
            .GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id);

        if (organizationAutoConfirmPolicyRequirement

View on GitHub (pinned to e93b962371)

Solutions

  1. Check Status == ProviderUserStatusType.Invited before calling AcceptUserAsync.
  2. Treat already-accepted as an idempotent success/no-op in the UI.
  3. Disable the accept button after first use.

Example fix

// before
await _providerService.AcceptUserAsync(providerUserId, user, token);

// after
if (providerUser.Status != ProviderUserStatusType.Invited) return; // already accepted
await _providerService.AcceptUserAsync(providerUserId, user, token);
Defensive patterns

Strategy: validation

Validate before calling

var providerUser = await _providerUserRepository.GetByIdAsync(providerUserId);
if (providerUser is { Status: not ProviderUserStatusType.Invited })
    return; // already accepted — idempotent

Type guard

static bool IsInviteAwaitingAcceptance(ProviderUser? pu) =>
    pu is { Status: ProviderUserStatusType.Invited };

Try / catch

try { await _providerService.AcceptUserAsync(providerUserId, user, token); }
catch (BadRequestException ex) when (ex.Message == "Already accepted.")
{ /* treat as success */ }

Prevention

When it happens

Trigger: Clicking an already-used accept link; double-submit; the user was already confirmed by a provider admin.

Common situations: Resent/reloaded accept URL; race between self-accept and admin confirmation.

Related errors


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