bitwarden/server · error · Exception
CannotFindEmailClaim
Error message
CannotFindEmailClaim
What it means
Thrown in AccountController.CreateUserAndOrgUserConditionallyAsync (line 542) on the JIT-provisioning path when no manual linking userIdentifier was provided (it is null/whitespace) and TryGetEmailAddress returned no email from the claims or providerUserId. An email is required to look up or create the user.
Source
Thrown at bitwarden_license/src/Sso/Controllers/AccountController.cs:542
/// <exception cref="Exception">An exception if the user cannot be provisioned as requested.</exception>
private async Task<(User resolvedUser, Organization foundOrganization, OrganizationUser foundOrgUser)> CreateUserAndOrgUserConditionallyAsync(
string provider,
string providerUserId,
IEnumerable<Claim> claims,
string userIdentifier,
SsoConfigurationData ssoConfigData
)
{
// Try to get the email from the claims as we don't know if we have a user record yet.
var name = GetName(claims, ssoConfigData.GetAdditionalNameClaimTypes());
var email = TryGetEmailAddress(claims, ssoConfigData, providerUserId);
User? possibleExistingUser;
if (string.IsNullOrWhiteSpace(userIdentifier))
{
if (string.IsNullOrWhiteSpace(email))
{
throw new Exception(_i18nService.T("CannotFindEmailClaim"));
}
possibleExistingUser = await _userRepository.GetByEmailAsync(email);
}
else
{
possibleExistingUser = await GetUserFromManualLinkingDataAsync(userIdentifier);
}
// Find the org (we error if we can't find an org because no org is not valid)
var organization = await GetOrganizationByProviderAsync(provider);
// Try to find an org user (null org user possible and valid here)
var possibleOrgUser = await GetOrganizationUserByUserAndOrgIdOrEmailAsync(possibleExistingUser, organization.Id, email);
//----------------------------------------------------
// Scenario 1: We've found the user in the User table
//----------------------------------------------------View on GitHub (pinned to e93b962371)
Solutions
- Configure the IdP to emit an email claim (email, mail, or a custom attribute mapped in additional email claim types).
- If the providerUserId is email-like, ensure it contains '@' so the fallback in TryGetEmailAddress applies.
- Add the IdP's email attribute name to the SSO config's additional email claim types list.
- For manual SSO linking, ensure the userIdentifier query parameter is passed.
Defensive patterns
Strategy: validation
Validate before calling
var email = TryGetEmailAddress(claims, ssoConfigData, providerUserId);
if (string.IsNullOrWhiteSpace(userIdentifier) && string.IsNullOrWhiteSpace(email))
return BadRequest("An email claim is required for JIT provisioning when no userIdentifier is provided."); Try / catch
try { await CreateUserAndOrgUserConditionallyAsync(provider, providerUserId, claims, userIdentifier, ssoConfigData); }
catch (Exception ex) when (ex.Message.Contains("CannotFindEmailClaim"))
{ /* instruct admin to configure email claim mapping in the IdP */ } Prevention
- Ensure the IdP emits an email claim (email, mail, or configured custom type).
- Map the IdP's email attribute name in the SSO config's additional email claim types.
- For providers where providerUserId is email-like, confirm it contains '@'.
When it happens
Trigger: The user has not authenticated with this SSO provider before (no SsoUser link), no userIdentifier query param is present for manual linking, and the claims contain no email claim nor a providerUserId containing '@'.
Common situations: IdP does not emit an email claim and the configuration's additional email claim types don't match; SAML/OIDC attribute mapping for email is incorrect; the providerUserId is a numeric ID without '@' so the fallback email guess fails.
Related errors
AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13).
Data as JSON: /api/errors/ab7830cf747bfaaf.
Report an issue: GitHub.