{"record":{"id":"6341f4990f3f51cc","repo":"Kareadita/Kavita","slug":"cannot-change-identity-provider-original-user","errorCode":"cannot-change-identity-provider-original-user","errorMessage":"cannot-change-identity-provider-original-user","messagePattern":"cannot-change-identity-provider-original-user","errorType":"exception","errorClass":"KavitaException","httpStatus":400,"severity":"warning","filePath":"Kavita.Services/AccountService.cs","lineNumber":127,"sourceCode":"    public async Task<bool> CanChangeAgeRestriction(AppUser? user, CancellationToken ct = default)\n    {\n        if (user == null) return false;\n\n        var roles = await userManager.GetRolesAsync(user);\n        if (roles.Contains(PolicyConstants.ReadOnlyRole)) return false;\n\n        return roles.Contains(PolicyConstants.ChangeRestrictionRole) || roles.Contains(PolicyConstants.AdminRole);\n    }\n\n    public async Task<bool> ChangeIdentityProvider(int actingUserId, AppUser user, IdentityProvider identityProvider,\n        CancellationToken ct = default)\n    {\n        var defaultAdminUser = await unitOfWork.UserRepository.GetDefaultAdminUser(ct: ct);\n        if (user.Id == defaultAdminUser.Id)\n        {\n            if (identityProvider == IdentityProvider.OpenIdConnect)\n            {\n                throw new KavitaException(await localizationService.TranslateAsync(actingUserId, \"cannot-change-identity-provider-original-user\"));\n            }\n\n            return false;\n        }\n\n        // Allow changes if users aren't being synced\n        var oidcSettings = (await unitOfWork.SettingsRepository.GetSettingsDtoAsync(ct)).OidcConfig;\n        if (!oidcSettings.SyncUserSettings)\n        {\n            user.IdentityProvider = identityProvider;\n            await unitOfWork.CommitAsync(ct);\n            return false;\n        }\n\n        // Don't allow changes to the user if they're managed by oidc, and their identity provider isn't being changed to something else\n        if (user.IdentityProvider == IdentityProvider.OpenIdConnect && identityProvider == IdentityProvider.OpenIdConnect)\n        {\n            throw new KavitaException(await localizationService.TranslateAsync(actingUserId, \"oidc-managed\"));","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/Kareadita/Kavita/blob/9c3e5400007f8a0282f7d883f2ad5e71716e514d/Kavita.Services/AccountService.cs#L109-L145","documentation":"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.","triggerScenarios":"An admin or sync flow attempts to set the default (original) admin account's IdentityProvider to OpenIdConnect via ChangeIdentityProvider.","commonSituations":"OIDC user-sync tries to convert the built-in admin to OIDC-managed; an admin UI action targeting the wrong (original) admin account.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"var defaultAdmin = await unitOfWork.UserRepository.GetDefaultAdminUser(ct);\nif (user.Id == defaultAdmin.Id && identityProvider == IdentityProvider.OpenIdConnect)\n    return BadRequest(\"cannot-change-identity-provider-original-user\");","typeGuard":null,"tryCatchPattern":"try { await accountService.ChangeIdentityProvider(actingUserId, user, provider, ct); }\ncatch (KavitaException ex) { return BadRequest(ex.Message); }","preventionTips":["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."],"tags":["oidc","account","admin","identity-provider","config"],"backgroundTag":null,"analyzedSha":"9c3e5400007f8a0282f7d883f2ad5e71716e514d","analyzedAt":"2026-08-13T19:06:05.897Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}