{"record":{"id":"2833010bfb8bd1ce","repo":"bitwarden/server","slug":"provider-is-already-setup","errorCode":null,"errorMessage":"Provider is already setup.","messagePattern":"Provider is already setup\\.","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"bitwarden_license/src/Commercial.Core/AdminConsole/Services/ProviderService.cs","lineNumber":114,"sourceCode":"        _organizationAbilityCacheService = organizationAbilityCacheService;\n        _providerAbilityCacheService = providerAbilityCacheService;\n        _providerBillingService = providerBillingService;\n        _pricingClient = pricingClient;\n        _providerClientOrganizationSignUpCommand = providerClientOrganizationSignUpCommand;\n        _policyRequirementQuery = policyRequirementQuery;\n    }\n\n    public async Task<Provider> CompleteSetupAsync(Provider provider, Guid ownerUserId, string token, string key, TokenizedPaymentMethod paymentMethod, BillingAddress billingAddress)\n    {\n        var owner = await _userService.GetUserByIdAsync(ownerUserId);\n        if (owner == null)\n        {\n            throw new BadRequestException(\"Invalid owner.\");\n        }\n\n        if (provider.Status != ProviderStatusType.Pending)\n        {\n            throw new BadRequestException(\"Provider is already setup.\");\n        }\n\n        if (!CoreHelpers.TokenIsValid(\"ProviderSetupInvite\", _dataProtector, token, owner.Email, provider.Id,\n            _globalSettings.OrganizationInviteExpirationHours))\n        {\n            throw new BadRequestException(\"Invalid token.\");\n        }\n\n        var providerUser = await _providerUserRepository.GetByProviderUserAsync(provider.Id, ownerUserId);\n        if (!(providerUser is { Type: ProviderUserType.ProviderAdmin }))\n        {\n            throw new BadRequestException(\"Invalid owner.\");\n        }\n\n        var organizationAutoConfirmPolicyRequirement = await _policyRequirementQuery\n            .GetAsync<AutomaticUserConfirmationPolicyRequirement>(ownerUserId);\n\n        if (organizationAutoConfirmPolicyRequirement","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/bitwarden_license/src/Commercial.Core/AdminConsole/Services/ProviderService.cs#L96-L132","documentation":"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).","triggerScenarios":"Calling CompleteSetupAsync a second time (double-submit), or on a provider already configured/Billable.","commonSituations":"Duplicate/retried POST after a successful setup; UI resubmission; concurrent setup attempts.","solutions":["Check provider.Status == ProviderStatusType.Pending before calling.","Treat already-setup as an idempotent success/no-op in the caller rather than an error.","Guard the client submit button to prevent double-posting."],"exampleFix":"// before\nawait _providerService.CompleteSetupAsync(provider, ownerUserId, token, key, payment, billing);\n\n// after\nif (provider.Status == ProviderStatusType.Billable) return; // already done\nawait _providerService.CompleteSetupAsync(provider, ownerUserId, token, key, payment, billing);","handlingStrategy":"validation","validationCode":"if (provider.Status != ProviderStatusType.Pending)\n    return; // already set up — idempotent no-op","typeGuard":null,"tryCatchPattern":"try { await _providerService.CompleteSetupAsync(provider, ownerUserId, token, key, payment, billing); }\ncatch (BadRequestException ex) when (ex.Message.Contains(\"already setup\"))\n{ /* treat as success — provider is configured */ }","preventionTips":["Check provider.Status == Pending before setup.","Make the setup endpoint idempotent for already-configured providers.","Disable the submit button client-side after first success."],"tags":["provider","setup","state-machine","idempotency","bitwarden"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}