bitwarden/server · error · BadRequestException
Invalid owner.
Error message
Invalid owner.
What it means
Thrown inside CompleteSetupAsync when _userService.GetUserByIdAsync(ownerUserId) returns null. The setup flow needs the owner to exist to validate the invite token against their email and to configure their ProviderUser record. BadRequestException (HTTP 400).
Solutions
- Verify the user exists before invoking setup (call IUserService.GetUserByIdAsync).
- Re-issue the setup invite for a valid existing user.
- Ensure the ownerUserId comes from the authenticated session, not a stale link.
Defensive patterns
Strategy: validation
Validate before calling
var owner = await _userService.GetUserByIdAsync(ownerUserId);
if (owner == null)
throw new InvalidOperationException($"Owner user '{ownerUserId}' does not exist."); Try / catch
try { await _providerService.CompleteSetupAsync(provider, ownerUserId, token, key, payment, billing); }
catch (BadRequestException ex) when (ex.Message == "Invalid owner.")
{ /* owner user missing — re-issue invite for a valid user */ } Prevention
- Derive ownerUserId from the authenticated session, not a stale link.
- Re-verify user existence right before setup.
- Clean up stale setup links when users are deleted.
When it happens
Trigger: CompleteSetupAsync invoked with an ownerUserId that was deleted, never existed, or belongs to a different environment.
Common situations: Stale setup link after the owner account was deleted; test fixtures with wrong user IDs; cross-environment ID leakage.
Related errors
- Invalid owner. Owner must be an existing Bitwarden user.
- An organization the user is a part of has enabled Automatic…
- Failed to remove organization vault. Please contact support.
- Invalid token.
- Invite the user first.
AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13).
Data as JSON: /api/errors/e35448b843023f70.
Report an issue: GitHub.
Appendix: source
Thrown at bitwarden_license/src/Commercial.Core/AdminConsole/Services/ProviderService.cs:109
_globalSettings = globalSettings;
_dataProtector = dataProtectionProvider.CreateProtector("ProviderServiceDataProtector");
_currentContext = currentContext;
_stripeAdapter = stripeAdapter;
_providerDeleteTokenDataFactory = providerDeleteTokenDataFactory;
_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.");
}View on GitHub (pinned to e93b962371)