{"record":{"id":"7e5f510794ec658f","repo":"Kareadita/Kavita","slug":"series-doesnt-exist-7e5f51","errorCode":"series-doesnt-exist","errorMessage":"series-doesnt-exist","messagePattern":"series-doesnt-exist","errorType":"exception","errorClass":"KavitaException","httpStatus":400,"severity":"error","filePath":"Kavita.Services/SeriesService.cs","lineNumber":528,"sourceCode":"        }\n        catch (Exception ex)\n        {\n            logger.LogError(ex, \"There was an issue when trying to delete multiple series\");\n            return false;\n        }\n    }\n\n    /// <summary>\n    /// This generates all the arrays needed by the Series Detail page in the UI. It is a specialized API for the unique layout constraints.\n    /// </summary>\n    /// <param name=\"seriesId\"></param>\n    /// <param name=\"userId\"></param>\n    /// <param name=\"ct\"></param>\n    /// <returns></returns>\n    public async Task<SeriesDetailDto> GetSeriesDetail(int seriesId, int userId, CancellationToken ct = default)\n    {\n        var series = await unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId, ct);\n        if (series == null) throw new KavitaException(await localizationService.TranslateAsync(userId, \"series-doesnt-exist\"));\n\n        var libraryIds = await unitOfWork.LibraryRepository.GetLibraryIdsForUserIdAsync(userId, ct: ct);\n        if (!libraryIds.Contains(series.LibraryId))\n            throw new UnauthorizedAccessException(\"user-no-access-library-from-series\");\n\n        var user = await unitOfWork.UserRepository.GetUserByIdAsync(userId, ct: ct);\n        if (user!.AgeRestriction != AgeRating.NotApplicable)\n        {\n            var seriesMetadata = await unitOfWork.SeriesRepository.GetSeriesMetadataAsync(seriesId, ct);\n            if (seriesMetadata!.AgeRating > user.AgeRestriction)\n                throw new UnauthorizedAccessException(\"series-restricted-age-restriction\");\n        }\n\n\n        var libraryType = await unitOfWork.LibraryRepository.GetLibraryTypeAsync(series.LibraryId, ct);\n        var volumes = await unitOfWork.VolumeRepository.GetVolumesDtoAsync(seriesId, userId, ct: ct);\n        var namingContext = await LocalizedNamingContext.CreateAsync(namingService, localizationService, userId, libraryType);\n        var bookTreatment = libraryType is LibraryType.Book or LibraryType.LightNovel;","sourceCodeStart":510,"sourceCodeEnd":546,"githubUrl":"https://github.com/Kareadita/Kavita/blob/9c3e5400007f8a0282f7d883f2ad5e71716e514d/Kavita.Services/SeriesService.cs#L510-L546","documentation":"Thrown by SeriesService.GetSeriesDetail when GetSeriesDtoByIdAsync returns null for the given seriesId. It uses the localization service to translate 'series-doesnt-exist' per user, so the message is localized rather than hard-coded. It signals the series was deleted, never existed, or is not visible to the lookup.","triggerScenarios":"GET series detail for a seriesId that returns no DTO - series was deleted, id is wrong, or the query (which is user/library scoped) found no row.","commonSituations":"Stale client bookmark to a deleted series; race between deletion and a detail fetch; wrong seriesId from a malformed link; or the user has no access and the scoped query returns null.","solutions":["Confirm the seriesId still exists via a series list call before opening detail.","Handle the localized KavitaException in the client and navigate the user back to the library.","If the series should exist, verify the user's library access and that the series wasn't filtered out.","Clear stale client-side caches/links pointing at removed series."],"exampleFix":"// before\nvar detail = await seriesService.GetSeriesDetail(seriesId, userId);\n\n// after\nvar series = await unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId, ct);\nif (series is null) return NotFound(localizer[\"series-doesnt-exist\"]);\nvar detail = await seriesService.GetSeriesDetail(seriesId, userId, ct);","handlingStrategy":"validation","validationCode":"var series = await unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId, ct);\nif (series is null) return NotFound(localizer[\"series-doesnt-exist\"]);\nvar detail = await seriesService.GetSeriesDetail(seriesId, userId, ct);","typeGuard":"static bool SeriesExists(SeriesDto? s) => s is not null;","tryCatchPattern":"try { return await seriesService.GetSeriesDetail(seriesId, userId, ct); }\ncatch (KavitaException ex) when (ex.Message.Contains(\"series-doesnt-exist\"))\n{ return NotFound(ex.Message); }","preventionTips":["Verify seriesId via a list call before opening detail.","Clear client caches referencing deleted series.","Handle the localized message and redirect to the library."],"tags":["series","not-found","localization","validation"],"backgroundTag":null,"analyzedSha":"9c3e5400007f8a0282f7d883f2ad5e71716e514d","analyzedAt":"2026-08-13T19:06:05.897Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}