Kareadita/Kavita · warning · KavitaException
cannot-change-identity-provider-original-user
cannot-change-identity-provider-original-user
Error message
cannot-change-identity-provider-original-user
What it means
Thrown as KavitaException with localized key 'cannot-change-identity-provider-original-user' by AccountService.ChangeIdentityProvider when the target user is the default admin user AND the requested provider is OpenIdConnect. Prevents locking the original admin out of local login.
Source
Thrown at Kavita.Services/AccountService.cs:127
public async Task<bool> CanChangeAgeRestriction(AppUser? user, CancellationToken ct = default)
{
if (user == null) return false;
var roles = await userManager.GetRolesAsync(user);
if (roles.Contains(PolicyConstants.ReadOnlyRole)) return false;
return roles.Contains(PolicyConstants.ChangeRestrictionRole) || roles.Contains(PolicyConstants.AdminRole);
}
public async Task<bool> ChangeIdentityProvider(int actingUserId, AppUser user, IdentityProvider identityProvider,
CancellationToken ct = default)
{
var defaultAdminUser = await unitOfWork.UserRepository.GetDefaultAdminUser(ct: ct);
if (user.Id == defaultAdminUser.Id)
{
if (identityProvider == IdentityProvider.OpenIdConnect)
{
throw new KavitaException(await localizationService.TranslateAsync(actingUserId, "cannot-change-identity-provider-original-user"));
}
return false;
}
// Allow changes if users aren't being synced
var oidcSettings = (await unitOfWork.SettingsRepository.GetSettingsDtoAsync(ct)).OidcConfig;
if (!oidcSettings.SyncUserSettings)
{
user.IdentityProvider = identityProvider;
await unitOfWork.CommitAsync(ct);
return false;
}
// Don't allow changes to the user if they're managed by oidc, and their identity provider isn't being changed to something else
if (user.IdentityProvider == IdentityProvider.OpenIdConnect && identityProvider == IdentityProvider.OpenIdConnect)
{
throw new KavitaException(await localizationService.TranslateAsync(actingUserId, "oidc-managed"));View on GitHub (pinned to 9c3e540000)
Solutions
- Do not convert the original default admin account to OIDC — keep a local admin for recovery.
- Target a non-default admin account if OIDC conversion is required.
- If the original admin truly must be OIDC, change the default-admin reference first, then retry.
Defensive patterns
Strategy: validation
Validate before calling
var defaultAdmin = await unitOfWork.UserRepository.GetDefaultAdminUser(ct);
if (user.Id == defaultAdmin.Id && identityProvider == IdentityProvider.OpenIdConnect)
return BadRequest("cannot-change-identity-provider-original-user"); Try / catch
try { await accountService.ChangeIdentityProvider(actingUserId, user, provider, ct); }
catch (KavitaException ex) { return BadRequest(ex.Message); } Prevention
- Keep the original admin on local login for recovery.
- Target non-default admins for OIDC conversion.
- Surface which account is the default admin in the UI.
When it happens
Trigger: An admin or sync flow attempts to set the default (original) admin account's IdentityProvider to OpenIdConnect via ChangeIdentityProvider.
Common situations: OIDC user-sync tries to convert the built-in admin to OIDC-managed; an admin UI action targeting the wrong (original) admin account.
Related errors
- oidc-managed
- errors.oidc.no-account
- oidc-invalid-authority
- User is not authenticated
- errors.oidc.missing-external-id
AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13).
Data as JSON: /api/errors/6341f4990f3f51cc.
Report an issue: GitHub.