{"record":{"id":"242087d7fd840c4c","repo":"Kareadita/Kavita","slug":"cant-delete-default-profile","errorCode":null,"errorMessage":"cant-delete-default-profile","messagePattern":"cant-delete-default-profile","errorType":"exception","errorClass":"KavitaException","httpStatus":500,"severity":"warning","filePath":"Kavita.Services/Reading/ReadingProfileService.cs","lineNumber":181,"sourceCode":"        newProfile.Name = $\"Implicit Profile for {seriesId}\";\n        newProfile.NormalizedName = newProfile.Name.ToNormalized();\n        if (activeDeviceId != null)\n        {\n            newProfile.DeviceIds.Add(activeDeviceId.Value);\n        }\n\n        user.ReadingProfiles.Add(newProfile);\n        await unitOfWork.CommitAsync();\n\n        return mapper.Map<UserReadingProfileDto>(newProfile);\n    }\n\n    public async Task DeleteReadingProfile(int userId, int profileId)\n    {\n        var profile = await unitOfWork.AppUserReadingProfileRepository.GetUserProfile(userId, profileId);\n        if (profile == null) throw new KavitaException(\"profile-doesnt-exist\");\n\n        if (profile.Kind == ReadingProfileKind.Default) throw new KavitaException(\"cant-delete-default-profile\");\n\n        unitOfWork.AppUserReadingProfileRepository.Remove(profile);\n        await unitOfWork.CommitAsync();\n    }\n\n    public async Task SetSeriesProfiles(int userId, List<int> profileIds, int seriesId)\n    {\n        var profiles = await unitOfWork.AppUserReadingProfileRepository.GetProfilesForUser(userId);\n\n        var selectedProfiles = profiles\n            .Where(rp => profileIds.Contains(rp.Id))\n            .ToList();\n        if (selectedProfiles.Count != profileIds.Count) throw new KavitaException(\"profile-doesnt-exist\");\n\n        DeviceOverlapGuard(selectedProfiles);\n\n        var allDeviceIds = selectedProfiles.SelectMany(p => p.DeviceIds).Distinct().ToList();\n","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/Kareadita/Kavita/blob/9c3e5400007f8a0282f7d883f2ad5e71716e514d/Kavita.Services/Reading/ReadingProfileService.cs#L163-L199","documentation":"Thrown by DeleteReadingProfile when the resolved profile has Kind == ReadingProfileKind.Default. The Default profile is system-managed and cannot be removed; only User (and Implicit-promoted) profiles are deletable. The 'cant-delete-default-profile' localization key is surfaced. This is a business-rule guard, not a data fault.","triggerScenarios":"The UI or API client issues a delete against the user's Default reading profile.","commonSituations":"Misconfigured UI offering delete on the default profile; scripted/admin call targeting the default id; user misunderstanding that the default is permanent.","solutions":["Do not attempt to delete the Default profile; it is permanent.","Disable/hide the delete control when profile.Kind == Default in the UI.","If custom settings are wanted, edit the Default profile or create a new User profile instead."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"var profile = await unitOfWork.AppUserReadingProfileRepository.GetUserProfile(userId, profileId);\nif (profile?.Kind == ReadingProfileKind.Default) return BadRequest(\"cant-delete-default-profile\");\nawait profileService.DeleteReadingProfile(userId, profileId);","typeGuard":"public static bool IsDeletable(AppUserReadingProfile p) => p.Kind != ReadingProfileKind.Default;","tryCatchPattern":"try { await profileService.DeleteReadingProfile(userId, profileId); }\ncatch (KavitaException ex) when (ex.Message == \"cant-delete-default-profile\") { return BadRequest(ex.Message); }","preventionTips":["Hide/disable the delete control for the Default profile in the UI.","Never target the Default profile id in scripted deletes.","Edit the Default profile or create a User profile instead of deleting."],"tags":["reading-profiles","business-rule","validation","delete"],"backgroundTag":null,"analyzedSha":"9c3e5400007f8a0282f7d883f2ad5e71716e514d","analyzedAt":"2026-08-13T19:06:05.897Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}