Kareadita/Kavita · error · KavitaException

generic-error

Error message

generic-error

What it means

Thrown by GetEstimateToCompletionForChapter when either the series DTO or chapter DTO lookup returns null. The message is the localized 'generic-error' ('Something went wrong, please try again') resolved per-user via localizationService.TranslateAsync. It is a catch-all guard before computing reading-time estimates.

Source

Thrown at Kavita.Services/Reading/ReaderService.cs:611

        {
            if (next)
            {
                return chapter.Id;
            }

            var chapterNum = accessor(chapter);
            if (currentChapterNumber.Equals(chapterNum)) next = true;
        }

        return -1;
    }

    public async Task<HourEstimateRangeDto> GetEstimateToCompletionForChapter(int userId, int seriesId, int chapterId)
    {
        var series = await unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId);
        var chapter = await unitOfWork.ChapterRepository.GetChapterDtoAsync(chapterId, userId);
        if (series == null || chapter == null)
            throw new KavitaException(await localizationService.TranslateAsync(userId, "generic-error"));

        if (series.Format == MangaFormat.Epub)
        {
            // Get the word counts for all the pages
            var pageCounts = await bookService.GetWordCountsPerPage(chapter.Files.First().FilePath); // TODO: Cache
            if (pageCounts == null) return GetTimeEstimate(chapter.WordCount, 0, true);

            // Sum character counts for unread pages
            var toReadCharacters = pageCounts
                .Where(kvp => kvp.Key > chapter.PagesRead)
                .Sum(kvp => kvp.Value);

            var wordsLeft = WordCountAnalyzerService.GetWordCount(toReadCharacters);
            return GetTimeEstimate(wordsLeft, 0, true);
        }

        var pagesLeft = chapter.Pages - chapter.PagesRead;

View on GitHub (pinned to 9c3e540000)

Solutions

  1. Verify seriesId and chapterId are valid and accessible to the user before requesting the estimate.
  2. Refresh the series/chapter data in the client after a library scan.
  3. If the error is unexpected, check logs for which of series/chapter was null and re-import the missing entity.
Defensive patterns

Strategy: validation

Validate before calling

var series = await unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId);
var chapter = await unitOfWork.ChapterRepository.GetChapterDtoAsync(chapterId, userId);
if (series == null || chapter == null) return null; // nothing to estimate
return await readerService.GetEstimateToCompletionForChapter(userId, seriesId, chapterId);

Type guard

public static bool ResolvesBoth(SeriesDto? s, ChapterDto? c) => s is not null && c is not null;

Try / catch

try { return await readerService.GetEstimateToCompletionForChapter(userId, seriesId, chapterId); }
catch (KavitaException) { return null; // estimate unavailable, degrade gracefully }

Prevention

When it happens

Trigger: Estimate endpoint called with a seriesId or chapterId that does not resolve (deleted, no access, stale id), or the chapter does not belong to the series/user.

Common situations: UI requests a time-to-complete estimate for a chapter that was just removed by a rescan; a stale chapter id cached in the client; user lacks access to the series' library.

Related errors


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