Kareadita/Kavita · error · KavitaException

series-doesnt-exist

Error message

series-doesnt-exist

What it means

Thrown in the same rebuild branch: the volume exists and carries a SeriesId, but GetSeriesDtoByIdAsync returns null. The volume points at a missing series — the top of the orphan chain. Reaching here means chapter and volume resolved but series did not, which is rare and indicates a broken volume → series link.

Source

Thrown at Kavita.Services/KoreaderService.cs:51

            userId, koreaderBookDto.progress.Sanitize(), koreaderBookDto.document.Sanitize());
        var file = await unitOfWork.MangaFileRepository.GetByKoreaderHash(koreaderBookDto.document, ct);
        if (file == null)
        {
            logger.LogWarning("KOReader progress for unknown book: {BookHash}. Run a force scan on the series to generate KOReader hashes", koreaderBookDto.document.Sanitize());
            throw new KavitaException(await localizationService.TranslateAsync(userId, "file-missing"));
        }

        var userProgressDto = await unitOfWork.AppUserProgressRepository.GetUserProgressDtoAsync(file.ChapterId, userId, ct);
        if (userProgressDto == null)
        {
            var chapterDto = await unitOfWork.ChapterRepository.GetChapterDtoAsync(file.ChapterId, userId, ct);
            if (chapterDto == null) throw new KavitaException(await localizationService.TranslateAsync(userId, "chapter-doesnt-exist"));

            var volumeDto = await unitOfWork.VolumeRepository.GetVolumeByIdAsync(chapterDto.VolumeId, ct: ct);
            if (volumeDto == null) throw new KavitaException(await localizationService.TranslateAsync(userId, "volume-doesnt-exist"));

            var seriesDto = await unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(volumeDto.SeriesId, userId, ct);
            if (seriesDto == null) throw new KavitaException(await localizationService.TranslateAsync(userId, "series-doesnt-exist"));

            userProgressDto = new ProgressDto()
            {
                PageNum = 0, // This is updated in KoreaderHelper.UpdateProgressDto
                ChapterId = file.ChapterId,
                VolumeId = chapterDto.VolumeId,
                SeriesId = seriesDto.Id,
                LibraryId = seriesDto.LibraryId
            };
        }

        // Update the bookScrollId if possible
        var reportedProgress = koreaderBookDto.progress;
        KoreaderHelper.UpdateProgressDto(userProgressDto, koreaderBookDto.progress);

        logger.LogDebug("Converted KOReader progress from {ProgressEncoding} to Page {PageNum} with ScrollId: {ScrollId}. For Chapter {ChapterId} in Series {SeriesId}",
            reportedProgress.Sanitize(), userProgressDto.PageNum, userProgressDto.BookScrollId?.Sanitize() ?? string.Empty,
            userProgressDto.ChapterId, userProgressDto.SeriesId);

View on GitHub (pinned to 9c3e540000)

Solutions

  1. Force-scan the library to rebuild the full series → volume → chapter → file hierarchy.
  2. Check the DB for volumes whose SeriesId has no matching series row; clean up or reparent.
  3. If the series was deleted intentionally, ensure its volumes/chapters/manga_files were also removed.
  4. Surface a clear 'rescan required' message to the end user rather than retrying the sync.
Defensive patterns

Strategy: try-catch

Validate before calling

var series = await unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(volume.SeriesId, userId, ct);
if (series == null)
    return Conflict(new { error = "series-doesnt-exist", hint = "Rescan the library." });

Try / catch

try { await koreaderService.SaveProgress(dto, userId, ct); }
catch (KavitaException ex) when (ex.Message.Contains("series-doesnt-exist"))
{ /* full library rescan; do not retry until hierarchy rebuilt */ }

Prevention

When it happens

Trigger: KOReader SaveProgress with a volume whose SeriesId is absent from the series table (deleted series with orphaned volumes, partial restore).

Common situations: Series deleted but volumes/chapters left behind; interrupted scan/refresh left the hierarchy half-built; manual DB surgery removed a series without cascading.

Related errors


AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13). Data as JSON: /api/errors/100f8b55b8bf1159. Report an issue: GitHub.