Kareadita/Kavita · error · KavitaException
errors.oidc.failed-to-update-email
Error message
errors.oidc.failed-to-update-email
What it means
Thrown by OidcService.SyncEmail when ASP.NET Identity's userManager.SetEmailAsync(user, email) returns a result with Succeeded=false. This indicates the Identity layer rejected the email change — typically due to a validation failure in a custom IUserValidator, an email-format rule, or an Identity configuration constraint. The detailed errors are logged with the user ID but not surfaced to the user beyond this generic message.
Source
Thrown at Kavita.Services/OidcService.cs:443
{
throw new KavitaException("errors.oidc.email-not-verified");
}
// Ensure no other user uses this email
var other = await userManager.FindByEmailAsync(email);
if (other != null)
{
throw new KavitaException("errors.oidc.email-in-use");
}
// The email is verified, we can go ahead and change & confirm it
if (claimsPrincipal.HasVerifiedEmail())
{
var res = await userManager.SetEmailAsync(user, email);
if (!res.Succeeded)
{
logger.LogError("Failed to update email for user {UserId} from OIDC {Errors}", user.Id, res.Errors.Select(x => x.Description).ToList());
throw new KavitaException("errors.oidc.failed-to-update-email");
}
user.EmailConfirmed = true;
await userManager.UpdateAsync(user);
return;
}
var token = await userManager.GenerateEmailConfirmationTokenAsync(user);
var isValidEmailAddress = !string.IsNullOrEmpty(user.Email) && emailService.IsValidEmail(user.Email);
var isEmailSetup = (await unitOfWork.SettingsRepository.GetSettingsDtoAsync()).IsEmailSetup();
var shouldEmailUser = isEmailSetup || !isValidEmailAddress;
user.EmailConfirmed = !shouldEmailUser;
user.ConfirmationToken = token;
await userManager.UpdateAsync(user);
var emailLink = await emailService.GenerateEmailLink(request, user.ConfirmationToken, "confirm-email-update", email);
logger.LogCritical("[Update Email]: Automatic email update after OIDC sync, email Link for {UserId}: {Link}", user.Id, emailLink);View on GitHub (pinned to 9c3e540000)
Solutions
- Check Kavita logs for the line 'Failed to update email for user {UserId} from OIDC {Errors}' — the Errors list contains the IdentityError descriptions that explain the rejection.
- Address the specific Identity error (e.g., if a custom validator rejected the domain, adjust the validator or the email).
- If the error is a DB constraint violation, check for duplicate Email rows and clean them up.
- Ensure no custom IUserValidator or IdentityOptions configuration is interfering with email assignment.
- Retry the login after resolving the underlying validation issue; the email sync will re-attempt on next OIDC login.
Example fix
// No code fix for the caller — root cause is in Identity configuration.
// Check logs for the IdentityError descriptions:
// "Failed to update email for user 42 from OIDC ["Email domain not allowed"]
// Then either fix the validator or the email value.
// If you have a custom validator, ensure it allows valid IdP emails:
services.Configure<IdentityOptions>(o =>
{
o.User.RequireUniqueEmail = true; // already the default
// remove any overly restrictive custom validators
}); Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-validate that the email will pass Identity validation:
// var emailValidator = serviceProvider.GetRequiredService<IUserValidator<AppUser>>();
// var result = await emailValidator.ValidateAsync(userManager, user with { Email = newEmail });
// if (!result.Succeeded)
// LogWarning("Email will be rejected by Identity: {Errors}",
// result.Errors.Select(e => e.Description)); Try / catch
// try { await oidcService.SyncUserSettings(...); }
// catch (KavitaException ex) when (ex.Message.Contains("failed-to-update-email"))
// {
// // Check logs for IdentityError descriptions.
// // Email sync failed but login may continue.
// logger.LogWarning("Email sync rejected by Identity for user {UserId}", user.Id);
// } Prevention
- Ensure no custom IUserValidator imposes rules stricter than the IdP's email format.
- Keep the database's Email column unique-index in sync with EF Core's configuration.
- Check logs for the 'Failed to update email' line with IdentityError descriptions after OIDC login failures.
- Test email sync in staging with the production IdP's actual email claims.
- Avoid manual DB edits to the Email column that could cause constraint violations.
When it happens
Trigger: The email passed all prior checks (verified, not in use by another user), but userManager.SetEmailAsync returns IdentityResult with one or more IdentityError objects. This can happen if a custom user validator rejects the email format, if IdentityOptions.User settings impose restrictions, or if a DB unique constraint fires at the EF level and surfaces through Identity.
Common situations: A custom IUserValidator<AppUser> is registered that enforces domain allow-lists or format rules stricter than the default. The database has a manual unique index on the Email column that conflicts with EF's expectation. A race condition where another user's email was committed between the FindByEmailAsync check and the SetEmailAsync call.
Related errors
- errors.oidc.failed-to-update-username
- send-to-kavita-email
- errors.oidc.missing-email
- errors.oidc.syncing-user
- errors.oidc.no-account
AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13).
Data as JSON: /api/errors/faa22b41ec43d651.
Report an issue: GitHub.