Kareadita/Kavita · error · KavitaException
errors.oidc.failed-to-update-username
Error message
errors.oidc.failed-to-update-username
What it means
Thrown by OidcService.SyncUsername when userManager.SetUserNameAsync(user, bestName) returns Succeeded=false. FindBestAvailableName selected a candidate name from the token claims (preferred_username, name, given_name, or surname), and the name passed the IsNameAvailable check, but Identity's username validator rejected the final SetUserNameAsync call. This can happen when IdentityOptions.User.AllowedUserNameCharacters or a custom IUserValidator rejects characters in the name.
Source
Thrown at Kavita.Services/OidcService.cs:503
}
catch (Exception)
{
/* Swallow exception */
}
}
private async Task SyncUsername(ClaimsPrincipal claimsPrincipal, AppUser user)
{
var bestName = await FindBestAvailableName(claimsPrincipal, user.UserName);
if (bestName == null || bestName == user.UserName) return;
var res = await userManager.SetUserNameAsync(user, bestName);
if (!res.Succeeded)
{
logger.LogError("Failed to update username for user {UserId} to {NewUserName} from OIDC {Errors}", user.Id,
bestName.Censor(), res.Errors.Select(x => x.Description).ToList());
throw new KavitaException("errors.oidc.failed-to-update-username");
}
}
private async Task SyncRoles(OidcConfigDto settings, ClaimsPrincipal claimsPrincipal, AppUser user)
{
var rolesFromToken = claimsPrincipal.GetClaimsWithPrefix(settings.RolesClaim, settings.RolesPrefix);
var roles = PolicyConstants.ValidRoles
.Where(s => rolesFromToken.Contains(s, StringComparer.OrdinalIgnoreCase))
.ToList();
// Ensure that Admin Role and ReadOnly aren't both selected
if (roles.Contains(PolicyConstants.AdminRole))
{
roles = roles.Where(r => r != PolicyConstants.ReadOnlyRole).ToList();
}
logger.LogDebug("Syncing access roles for user {UserId}, found roles {Roles}", user.Id, roles);View on GitHub (pinned to 9c3e540000)
Solutions
- Check Kavita logs for 'Failed to update username for user {UserId} to {NewUserName} from OIDC {Errors}' — the IdentityError descriptions reveal which character or rule was violated.
- Adjust the IdP claim to use a username with allowed characters (alphanumeric, dash, underscore, dot by default).
- If unicode usernames are desired, extend IdentityOptions.User.AllowedUserNameCharacters in Kavita's startup configuration to include the needed character ranges.
- Ensure Kavita's AccountService.ValidateUsername and Identity's default username validator agree on allowed characters to avoid the gap where one passes and the other fails.
- Disable username syncing in OIDC settings if the IdP usernames are incompatible with Kavita's constraints.
Example fix
// In Startup/Program configuration, widen allowed characters:
services.Configure<IdentityOptions>(opt =>
{
opt.User.AllowedUserNameCharacters =
"abcdefghijklmnopqrstuvwxyz" +
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"0123456789-._@+" + // add needed chars
"\u00e0\u00e1\u00e2"; // unicode example (add more ranges as needed)
});
// Or disable username sync in OIDC settings to avoid the conflict entirely. Defensive patterns
Strategy: validation
Validate before calling
// Pre-validate the candidate username against Identity's rules:
// var name = await oidcService.FindBestAvailableName(principal, user.UserName);
// if (name != null && name != user.UserName)
// {
// var result = await userManager.UserValidator.ValidateAsync(userManager, user with { UserName = name });
// if (!result.Succeeded)
// LogWarning("Username '{Name}' will be rejected by Identity", name);
// } Try / catch
// try { await oidcService.SyncUserSettings(...); }
// catch (KavitaException ex) when (ex.Message.Contains("failed-to-update-username"))
// {
// // Username sync failed; login continues with existing username.
// // Check logs for the IdentityError with character violations.
// logger.LogWarning("Username sync failed for user {UserId}", user.Id);
// } Prevention
- Ensure the IdP's preferred_username/name claims only use characters in IdentityOptions.User.AllowedUserNameCharacters.
- If unicode usernames are needed, extend AllowedUserNameCharacters in startup config.
- Align AccountService.ValidateUsername logic with Identity's default user validator to avoid gaps.
- Disable username sync if IdP usernames are incompatible with Kavita's constraints.
- Test with actual IdP usernames in staging before enabling in production.
When it happens
Trigger: The IdP token contains a preferred_username or name claim with characters not in IdentityOptions.User.AllowedUserNameCharacters (default is a restrictive ASCII set). FindBestAvailableName returns the name because IsNameAvailable (which calls ValidateUsername) didn't flag it, but SetUserNameAsync uses a different validation path that rejects it.
Common situations: The IdP username contains spaces, unicode characters, or special symbols (e.g., 'José', 'user@host', '名前'). Kavita's default AllowedUserNameCharacters excludes these. A custom username validator has stricter rules than ValidateUsername in AccountService, creating a gap where IsNameAvailable passes but SetUserNameAsync fails.
Related errors
- errors.oidc.failed-to-update-email
- oidc-invalid-authority
- User is not authenticated
- {comparison} is not applicable for {fieldName}
- Name must be set
AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13).
Data as JSON: /api/errors/7f0e8b83b8004456.
Report an issue: GitHub.