Kareadita/Kavita · error · KavitaException

chapter-doesnt-exist

Error message

chapter-doesnt-exist

What it means

Thrown inside the no-progress branch of KoreaderService.SaveProgress: the MangaFile exists and points at a ChapterId, but GetChapterDtoAsync for that chapter returns null. This means the file row references a chapter that no longer exists (orphaned FK). It surfaces only when a user has no prior progress on the chapter, since the progress-less branch rebuilds the entity graph (chapter → volume → series).

Source

Thrown at Kavita.Services/KoreaderService.cs:45

    /// <param name="koreaderBookDto"></param>
    /// <param name="userId"></param>
    /// <param name="ct"></param>
    public async Task SaveProgress(KoreaderBookDto koreaderBookDto, int userId, CancellationToken ct = default)
    {
        logger.LogDebug("Saving KOReader progress for User ({UserId}): {KoreaderProgress} - {KoreaderHash}",
            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

View on GitHub (pinned to 9c3e540000)

Solutions

  1. Re-scan the affected series so MangaFile rows are re-linked to current chapters.
  2. If inconsistent, run a library scan with 'force' to rebuild chapter-to-file mappings.
  3. Audit the DB: select MangaFile rows whose ChapterId has no matching chapter row, then either fix or delete the orphan.
  4. As a caller, catch KavitaException and surface 'rescan the series' to the user rather than retrying.
Defensive patterns

Strategy: try-catch

Validate before calling

var chapter = await unitOfWork.ChapterRepository.GetChapterDtoAsync(file.ChapterId, userId, ct);
if (chapter == null)
    return Conflict(new { error = "chapter-doesnt-exist", hint = "Rescan the series." });

Try / catch

try { await koreaderService.SaveProgress(dto, userId, ct); }
catch (KavitaException ex) when (ex.Message.Contains("chapter-doesnt-exist"))
{ /* log + trigger a rescan; tell the device to retry after scan completes */ }

Prevention

When it happens

Trigger: KOReader SaveProgress for a file whose MangaFile.ChapterId points at a deleted chapter — e.g. after a re-scan merged/split chapters and rewrote the chapter table while the manga_file row still carries the old ChapterId.

Common situations: Post-scan inconsistency: chapter was re-keyed but manga_file.ChapterId not updated; a manual DB edit removed a chapter; a volume/chapter recount left dangling MangaFile references.

Related errors


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