{"record":{"id":"c19e19396b3a1e54","repo":"Kareadita/Kavita","slug":"series-doesnt-exist-c19e19","errorCode":null,"errorMessage":"series-doesnt-exist","messagePattern":"series-doesnt-exist","errorType":"exception","errorClass":"KavitaException","httpStatus":500,"severity":"error","filePath":"Kavita.Services/Reading/ReadingProfileService.cs","lineNumber":110,"sourceCode":"        if (profileToPromote.Kind != ReadingProfileKind.Implicit) throw new KavitaException(\"profile-not-implicit\");\n\n        var seriesId = profileToPromote.SeriesIds[0]; // An Implicit series can only be bound to 1 Series\n\n        // Check if there are any reading profiles (Series) already bound to the series (and device)\n        var existingSeriesProfile = allUserProfiles\n            .Where(rp => rp.Kind == ReadingProfileKind.User)\n            .Where(rp => activeDeviceId == null || rp.DeviceIds.Contains(activeDeviceId.Value))\n            .FirstOrDefault(rp => rp.SeriesIds.Contains(seriesId));\n\n        if (existingSeriesProfile != null)\n        {\n            existingSeriesProfile.SeriesIds.Remove(seriesId);\n            unitOfWork.AppUserReadingProfileRepository.Update(existingSeriesProfile);\n        }\n\n        // Convert the implicit profile into a proper Series\n        var series = await unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId);\n        if (series == null) throw new KavitaException(\"series-doesnt-exist\"); // Shouldn't happen\n\n        profileToPromote.Kind = ReadingProfileKind.User;\n        profileToPromote.Name = await localizationService.TranslateAsync(userId, \"generated-reading-profile-name\", series.Name);\n        profileToPromote.Name = EnsureUniqueProfileName(allUserProfiles, profileToPromote.Name);\n        profileToPromote.NormalizedName = profileToPromote.Name.ToNormalized();\n        unitOfWork.AppUserReadingProfileRepository.Update(profileToPromote);\n\n        await unitOfWork.CommitAsync();\n\n        return mapper.Map<UserReadingProfileDto>(profileToPromote);\n    }\n\n    private static string EnsureUniqueProfileName(IList<AppUserReadingProfile> allUserProfiles, string name)\n    {\n        var counter = 1;\n        var newName = name;\n        while (allUserProfiles.Any(p => p.Name == newName))\n        {","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/Kareadita/Kavita/blob/9c3e5400007f8a0282f7d883f2ad5e71716e514d/Kavita.Services/Reading/ReadingProfileService.cs#L92-L128","documentation":"Thrown by PromoteImplicitProfile when the series bound to the implicit profile (profileToPromote.SeriesIds[0]) no longer exists in the DB. The code comment 'Shouldn't happen' marks it as an invariant-violation guard: an implicit profile should always reference a live series. The 'series-doesnt-exist' localization key is surfaced.","triggerScenarios":"The series tied to the implicit profile was deleted between profile creation and promotion, leaving a dangling reference in SeriesIds.","commonSituations":"Series removed by an admin/library rescan while an implicit profile lingered; data-integrity drift after migration; manual DB edits broke the reference.","solutions":["Delete or reset the orphaned implicit profile so it stops referencing the missing series.","Trigger a library scan to confirm series state, then recreate the implicit profile from the reader.","Investigate data integrity if this fires — the comment implies it should be unreachable."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"var series = await unitOfWork.SeriesRepository.GetSeriesByIdAsync(profileToPromote.SeriesIds[0]);\nif (series == null) { // clean up orphaned implicit profile instead of throwing\n    unitOfWork.AppUserReadingProfileRepository.Remove(profileToPromote);\n    await unitOfWork.CommitAsync();\n    return;\n}","typeGuard":null,"tryCatchPattern":"try { await profileService.PromoteImplicitProfile(userId, profileId, activeDeviceId); }\ncatch (KavitaException ex) when (ex.Message == \"series-doesnt-exist\") { _logger.LogError(\"Orphaned implicit profile {Id}\", profileId); return NotFound(); }","preventionTips":["Cascade-delete or reset implicit profiles when their series is removed.","Treat this throw as a data-integrity signal — investigate if it fires.","Validate series existence before dereferencing SeriesIds[0]."],"tags":["reading-profiles","series","data-integrity","implicit"],"backgroundTag":null,"analyzedSha":"9c3e5400007f8a0282f7d883f2ad5e71716e514d","analyzedAt":"2026-08-13T19:06:05.897Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}