{"record":{"id":"1ad65228a27ad864","repo":"Kareadita/Kavita","slug":"series-doesnt-exist-1ad652","errorCode":null,"errorMessage":"series-doesnt-exist","messagePattern":"series-doesnt-exist","errorType":"exception","errorClass":"KavitaException","httpStatus":500,"severity":"error","filePath":"Kavita.Services/Reading/ReaderService.cs","lineNumber":95,"sourceCode":"        user.Progresses ??= new List<AppUserProgress>();\n        foreach (var volume in volumes)\n        {\n            await MarkChaptersAsUnread(user, seriesId, volume.Chapters);\n        }\n    }\n\n    /// <summary>\n    /// Marks all Chapters as Read by creating or updating UserProgress rows. Does not commit.\n    /// </summary>\n    /// <remarks>Emits events to the UI for each chapter progress and one for each volume progress</remarks>\n    /// <param name=\"user\"></param>\n    /// <param name=\"seriesId\"></param>\n    /// <param name=\"chapters\"></param>\n    public async Task MarkChaptersAsRead(AppUser user, int seriesId, IList<Chapter> chapters)\n    {\n        var seenVolume = new Dictionary<int, bool>();\n        var series = await unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId);\n        if (series == null) throw new KavitaException(\"series-doesnt-exist\");\n\n        foreach (var chapter in chapters)\n        {\n            var userProgress = GetUserProgressForChapter(user, chapter);\n\n            if (userProgress == null)\n            {\n                user.Progresses.Add(new AppUserProgress\n                {\n                    PagesRead = chapter.Pages,\n                    VolumeId = chapter.VolumeId,\n                    SeriesId = seriesId,\n                    ChapterId = chapter.Id,\n                    LibraryId = series.LibraryId,\n                });\n            }\n            else\n            {","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/Kareadita/Kavita/blob/9c3e5400007f8a0282f7d883f2ad5e71716e514d/Kavita.Services/Reading/ReaderService.cs#L77-L113","documentation":"Thrown by MarkChaptersAsRead when GetSeriesByIdAsync(seriesId) returns null. The literal 'series-doesnt-exist' is a localization key surfaced to the UI. It guards a core read-progress mutation: if the series no longer exists, progress rows cannot be attached to it.","triggerScenarios":"A client requests marking chapters read for a seriesId that was deleted, that belongs to a library the user lacks access to (so the query returns nothing), or a stale/cached seriesId from before a library rescan that removed it.","commonSituations":"User had a series open in the web reader while an admin deleted it or rescanned it away; a third-party client cached an old series id; the series was moved between libraries and the old id reference is stale.","solutions":["Refresh the library list in the client to confirm the series still exists and is in an accessible library.","Verify the seriesId sent matches an existing Series row (and the user has library access).","If the series was deleted, discard the stale client reference and stop the mark-read call.","Trigger a library scan to ensure the series is re-imported if it should exist."],"exampleFix":"// before\nawait readerService.MarkChaptersAsRead(user, seriesId, chapters);\n\n// after: validate existence first\nvar series = await unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId);\nif (series == null) return NotFound(\"series-doesnt-exist\");\nawait readerService.MarkChaptersAsRead(user, seriesId, chapters);","handlingStrategy":"validation","validationCode":"var series = await unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId);\nif (series == null) return NotFound();\nawait readerService.MarkChaptersAsRead(user, seriesId, chapters);","typeGuard":"public static bool SeriesExists(Series? s) => s is not null;","tryCatchPattern":"try { await readerService.MarkChaptersAsRead(user, seriesId, chapters); }\ncatch (KavitaException ex) when (ex.Message == \"series-doesnt-exist\")\n{ return NotFound(\"Series no longer exists\"); }","preventionTips":["Validate seriesId against the DB (and user library access) before mutating progress.","Discard stale client references after library rescans/deletions.","Centralize series-existence checks in the API layer so callers can't pass dead ids."],"tags":["reading","series","data-integrity","not-found"],"backgroundTag":null,"analyzedSha":"9c3e5400007f8a0282f7d883f2ad5e71716e514d","analyzedAt":"2026-08-13T19:06:05.897Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}