bitwarden/server · warning · BadRequestException

Provider is already setup.

Error message

Provider is already setup.

What it means

Thrown inside CompleteSetupAsync when provider.Status is not Pending, meaning setup has already been completed. Setup is a one-time state transition from Pending to Billable. BadRequestException (HTTP 400).

Source

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

        _organizationAbilityCacheService = organizationAbilityCacheService;
        _providerAbilityCacheService = providerAbilityCacheService;
        _providerBillingService = providerBillingService;
        _pricingClient = pricingClient;
        _providerClientOrganizationSignUpCommand = providerClientOrganizationSignUpCommand;
        _policyRequirementQuery = policyRequirementQuery;
    }

    public async Task<Provider> CompleteSetupAsync(Provider provider, Guid ownerUserId, string token, string key, TokenizedPaymentMethod paymentMethod, BillingAddress billingAddress)
    {
        var owner = await _userService.GetUserByIdAsync(ownerUserId);
        if (owner == null)
        {
            throw new BadRequestException("Invalid owner.");
        }

        if (provider.Status != ProviderStatusType.Pending)
        {
            throw new BadRequestException("Provider is already setup.");
        }

        if (!CoreHelpers.TokenIsValid("ProviderSetupInvite", _dataProtector, token, owner.Email, provider.Id,
            _globalSettings.OrganizationInviteExpirationHours))
        {
            throw new BadRequestException("Invalid token.");
        }

        var providerUser = await _providerUserRepository.GetByProviderUserAsync(provider.Id, ownerUserId);
        if (!(providerUser is { Type: ProviderUserType.ProviderAdmin }))
        {
            throw new BadRequestException("Invalid owner.");
        }

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

        if (organizationAutoConfirmPolicyRequirement

View on GitHub (pinned to e93b962371)

Solutions

  1. Check provider.Status == ProviderStatusType.Pending before calling.
  2. Treat already-setup as an idempotent success/no-op in the caller rather than an error.
  3. Guard the client submit button to prevent double-posting.

Example fix

// before
await _providerService.CompleteSetupAsync(provider, ownerUserId, token, key, payment, billing);

// after
if (provider.Status == ProviderStatusType.Billable) return; // already done
await _providerService.CompleteSetupAsync(provider, ownerUserId, token, key, payment, billing);
Defensive patterns

Strategy: validation

Validate before calling

if (provider.Status != ProviderStatusType.Pending)
    return; // already set up — idempotent no-op

Try / catch

try { await _providerService.CompleteSetupAsync(provider, ownerUserId, token, key, payment, billing); }
catch (BadRequestException ex) when (ex.Message.Contains("already setup"))
{ /* treat as success — provider is configured */ }

Prevention

When it happens

Trigger: Calling CompleteSetupAsync a second time (double-submit), or on a provider already configured/Billable.

Common situations: Duplicate/retried POST after a successful setup; UI resubmission; concurrent setup attempts.

Related errors


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