Kareadita/Kavita · error · KavitaException

{archivePath} does not exist on disk

Error message

{archivePath} does not exist on disk

What it means

Thrown by ArchiveService.ExtractArchive (line 526) when directoryService.FileSystem.File.Exists(archivePath) is false at extraction time. Subtle: IsValidArchive (called at line 519) already returns false — and causes an early return — when System.IO.File.Exists is false, so reaching line 523 implies the file existed moments earlier. This branch is therefore mostly a TOCTOU (file deleted between the two checks) or a divergence between System.IO.File (used in IsValidArchive) and the abstracted directoryService.FileSystem (used here).

Source

Thrown at Kavita.Services/ArchiveService.cs:526

    /// <summary>
    /// Extracts an archive to a temp cache directory. Returns path to new directory. If temp cache directory already exists,
    /// will return that without performing an extraction. Returns empty string if there are any invalidations which would
    /// prevent operations to perform correctly (missing archivePath file, empty archive, etc).
    /// </summary>
    /// <param name="archivePath">A valid file to an archive file.</param>
    /// <param name="extractPath">Path to extract to</param>
    /// <returns></returns>
    public void ExtractArchive(string archivePath, string extractPath)
    {
        if (!IsValidArchive(archivePath)) return;

        if (directoryService.FileSystem.Directory.Exists(extractPath)) return;

        if (!directoryService.FileSystem.File.Exists(archivePath))
        {
            logger.LogError("{Archive} does not exist on disk", archivePath);
            throw new KavitaException($"{archivePath} does not exist on disk");
        }

        var sw = Stopwatch.StartNew();

        try
        {
            var libraryHandler = CanOpen(archivePath);
            switch (libraryHandler)
            {
                case ArchiveLibrary.Default:
                {
                    using var archive = ZipFile.OpenRead(archivePath);
                    ExtractArchiveEntries(archive, extractPath);
                    break;
                }
                case ArchiveLibrary.SharpCompress:
                {
                    using var archive = ArchiveFactory.OpenArchive(archivePath);

View on GitHub (pinned to 9c3e540000)

Solutions

  1. Confirm the archive still exists at archivePath right before calling ExtractArchive (re-resolve the path from the DB).
  2. Ensure the same filesystem abstraction is used for the existence check and the extraction.
  3. Rescan the library to refresh file paths if archives were moved on disk.

Example fix

// before — two different existence checks (System.IO.File vs directoryService.FileSystem)
if (!directoryService.FileSystem.File.Exists(archivePath)) {
    logger.LogError("{Archive} does not exist on disk", archivePath);
    throw new KavitaException($"{archivePath} does not exist on disk");
}

// after — resolve fresh path and use one consistent filesystem
if (!directoryService.FileSystem.File.Exists(archivePath)) {
    logger.LogError("{Archive} does not exist on disk", archivePath);
    throw new KavitaException($"{archivePath} does not exist on disk");
}
Defensive patterns

Strategy: validation

Validate before calling

// Re-resolve and check existence right before extraction using the same FS abstraction
if (!directoryService.FileSystem.File.Exists(archivePath))
    return; // or skip / 404 the reading request

Prevention

When it happens

Trigger: ExtractArchive called on a file that is deleted between IsValidArchive and the second existence check; or when directoryService.FileSystem is a different/abstraction whose existence semantics differ from System.IO.File. Used by ReadingItemService.Extract for archive (manga) reading and by CacheService extraction.

Common situations: Library rescan / file move deleting/replacing the archive mid-extraction; a custom IFileSystem in tests that disagrees with the real disk; network-mounted library where the file temporarily vanishes.

Related errors


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