Kareadita/Kavita · error · KavitaException
series-doesnt-exist
series-doesnt-exist
Error message
series-doesnt-exist
What it means
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.
Source
Thrown at Kavita.Services/SeriesService.cs:528
}
catch (Exception ex)
{
logger.LogError(ex, "There was an issue when trying to delete multiple series");
return false;
}
}
/// <summary>
/// This generates all the arrays needed by the Series Detail page in the UI. It is a specialized API for the unique layout constraints.
/// </summary>
/// <param name="seriesId"></param>
/// <param name="userId"></param>
/// <param name="ct"></param>
/// <returns></returns>
public async Task<SeriesDetailDto> GetSeriesDetail(int seriesId, int userId, CancellationToken ct = default)
{
var series = await unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId, ct);
if (series == null) throw new KavitaException(await localizationService.TranslateAsync(userId, "series-doesnt-exist"));
var libraryIds = await unitOfWork.LibraryRepository.GetLibraryIdsForUserIdAsync(userId, ct: ct);
if (!libraryIds.Contains(series.LibraryId))
throw new UnauthorizedAccessException("user-no-access-library-from-series");
var user = await unitOfWork.UserRepository.GetUserByIdAsync(userId, ct: ct);
if (user!.AgeRestriction != AgeRating.NotApplicable)
{
var seriesMetadata = await unitOfWork.SeriesRepository.GetSeriesMetadataAsync(seriesId, ct);
if (seriesMetadata!.AgeRating > user.AgeRestriction)
throw new UnauthorizedAccessException("series-restricted-age-restriction");
}
var libraryType = await unitOfWork.LibraryRepository.GetLibraryTypeAsync(series.LibraryId, ct);
var volumes = await unitOfWork.VolumeRepository.GetVolumesDtoAsync(seriesId, userId, ct: ct);
var namingContext = await LocalizedNamingContext.CreateAsync(namingService, localizationService, userId, libraryType);
var bookTreatment = libraryType is LibraryType.Book or LibraryType.LightNovel;View on GitHub (pinned to 9c3e540000)
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.
Example fix
// before var detail = await seriesService.GetSeriesDetail(seriesId, userId); // after var series = await unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId, ct); if (series is null) return NotFound(localizer["series-doesnt-exist"]); var detail = await seriesService.GetSeriesDetail(seriesId, userId, ct);
Defensive patterns
Strategy: validation
Validate before calling
var series = await unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId, ct); if (series is null) return NotFound(localizer["series-doesnt-exist"]); var detail = await seriesService.GetSeriesDetail(seriesId, userId, ct);
Type guard
static bool SeriesExists(SeriesDto? s) => s is not null;
Try / catch
try { return await seriesService.GetSeriesDetail(seriesId, userId, ct); }
catch (KavitaException ex) when (ex.Message.Contains("series-doesnt-exist"))
{ return NotFound(ex.Message); } Prevention
- Verify seriesId via a list call before opening detail.
- Clear client caches referencing deleted series.
- Handle the localized message and redirect to the library.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- library-doesnt-exist
- series-doesnt-exist
- series-doesnt-exist
- profile-does-not-exist
- Path not found in CBL repository: {path}
AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13).
Data as JSON: /api/errors/7e5f510794ec658f.
Report an issue: GitHub.