bitwarden/server · warning · BadRequestException

You cannot change your email when using Key Connector.

Error message

You cannot change your email when using Key Connector.

What it means

Thrown as a 400 BadRequestException("You cannot change your email when using Key Connector.") from the legacy (feature-flag-off) path of POST accounts/email-token when user.UsesKeyConnector is true. Key Connector users obtain their user key from an external IdP/key source rather than from a master password, so the legacy local email-change flow (which rotates the master password and wrapped key) does not apply.

Source

Thrown at src/Api/Auth/Controllers/AccountsController.cs:134

        var user = await _userService.GetUserByPrincipalAsync(User);
        if (user == null)
        {
            throw new UnauthorizedAccessException();
        }

        // TODO: PM-39120 - PM30806_SelfServiceChangeEmailCommand flag cleanup, remove the flag
        // check and keep only the SelfServiceChangeEmailCommand call.
        if (_featureService.IsEnabled(FeatureFlagKeys.PM30806_SelfServiceChangeEmailCommand))
        {
            await _selfServiceChangeEmailCommand.InitiateChangeEmailAsync(
                user, model.MasterPasswordHash, model.NewEmail);

            return;
        }

        if (user.UsesKeyConnector)
        {
            throw new BadRequestException("You cannot change your email when using Key Connector.");
        }

        if (!await _userService.CheckPasswordAsync(user, model.MasterPasswordHash))
        {
            await Task.Delay(2000);
            throw new BadRequestException("MasterPasswordHash", "Invalid password.");
        }

        var claimedUserValidationResult = await _userService.ValidateClaimedUserDomainAsync(user, model.NewEmail);

        if (!claimedUserValidationResult.Succeeded)
        {
            throw new BadRequestException(claimedUserValidationResult.Errors);
        }

        await _userService.InitiateEmailChangeAsync(user, model.NewEmail);
    }

View on GitHub (pinned to e93b962371)

Solutions

  1. Use the self-service change-email flow (the PM30806_SelfServiceChangeEmailCommand path) which supports Key Connector; ensure the feature flag is enabled.
  2. If Key Connector must stay, change the email at the IdP and have the user re-provision rather than via this endpoint.
  3. Update the client to a version that routes Key Connector users to the supported flow.

Example fix

// before: legacy endpoint rejects Key Connector users
await api.post('accounts/email-token', { newEmail, masterPasswordHash });
// after: use the self-service flow enabled by the feature flag
await api.post('accounts/email-token', { newEmail, masterPasswordHash }); // with flag PM30806 enabled server-side
Defensive patterns

Strategy: validation

Validate before calling

function canChangeEmailLocally(user, flagOn) {
  return !user.usesKeyConnector || flagOn;
}

Type guard

function isKeyConnectorUser(u): boolean { return !!u && u.usesKeyConnector === true; }

Prevention

When it happens

Trigger: A Key Connector-enabled user (SSO with Key Connector) calls POST accounts/email-token while the PM30806_SelfServiceChangeEmailCommand flag is OFF, hitting the legacy branch that rejects Key Connector accounts.

Common situations: SSO organization with Key Connector enabled; the client is on a build that still uses the legacy email-change endpoint; feature flag not yet rolled out to the deployment.

Related errors


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