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

  1. Do not convert the original default admin account to OIDC — keep a local admin for recovery.
  2. Target a non-default admin account if OIDC conversion is required.
  3. 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

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


AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13). Data as JSON: /api/errors/6341f4990f3f51cc. Report an issue: GitHub.