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 possibleView on GitHub (pinned to 9c3e540000)
Solutions
- Re-scan the affected series so MangaFile rows are re-linked to current chapters.
- If inconsistent, run a library scan with 'force' to rebuild chapter-to-file mappings.
- Audit the DB: select MangaFile rows whose ChapterId has no matching chapter row, then either fix or delete the orphan.
- 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
- Trigger a scan after any structural metadata change so chapter->file links stay consistent.
- Periodically check for orphaned manga_files (ChapterId with no chapter row).
- Avoid direct DB edits that delete chapters without cascading to manga_files.
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.