{"record":{"id":"2d8934c9ef5451f6","repo":"Kareadita/Kavita","slug":"source-file-not-found","errorCode":null,"errorMessage":"Source file not found","messagePattern":"Source file not found","errorType":"exception","errorClass":"FileNotFoundException","httpStatus":null,"severity":"error","filePath":"Kavita.Services/DirectoryService.cs","lineNumber":890,"sourceCode":"    {\n        foreach (var file in files)\n        {\n            try\n            {\n                FileSystem.FileInfo.New(file).Delete();\n            }\n            catch (Exception)\n            {\n                /* Swallow exception */\n            }\n        }\n    }\n\n    public void CopyFile(string sourcePath, string destinationPath, bool overwrite = true)\n    {\n        if (!File.Exists(sourcePath))\n        {\n            throw new FileNotFoundException(\"Source file not found\", sourcePath);\n        }\n\n        var destinationDirectory = Path.GetDirectoryName(destinationPath);\n        if (string.IsNullOrEmpty(destinationDirectory))\n        {\n            throw new ArgumentException(\"Destination path does not contain a directory\", nameof(destinationPath));\n        }\n\n        if (!Directory.Exists(destinationDirectory))\n        {\n            FileSystem.Directory.CreateDirectory(destinationDirectory);\n        }\n\n        FileSystem.File.Copy(sourcePath, destinationPath, overwrite);\n    }\n\n    /// <summary>\n    /// Returns the human-readable file size for an arbitrary, 64-bit file size","sourceCodeStart":872,"sourceCodeEnd":908,"githubUrl":"https://github.com/Kareadita/Kavita/blob/9c3e5400007f8a0282f7d883f2ad5e71716e514d/Kavita.Services/DirectoryService.cs#L872-L908","documentation":"A standard .NET FileNotFoundException thrown by CopyFile when the source file does not exist. The method checks File.Exists(sourcePath) before attempting the copy. Unlike KavitaException, this is a raw BCL exception that propagates as a 500 if uncaught. The source path is included as the fileName parameter of the exception.","triggerScenarios":"Source file was deleted or moved between the time it was enumerated and the copy was attempted; source path is misspelled or refers to a file on an unmounted share; file permissions prevent the Exists check from seeing the file.","commonSituations":"Race condition during library processing where files are modified by external tools; concurrent scans and user-initiated file operations; backup or sync tools modifying the library while Kavita reads it; temp files cleaned up before the copy completes.","solutions":["Verify the source file exists at the specified path before the operation","Ensure no external processes are modifying or deleting files in the library during operations","Wrap the CopyFile call in a try-catch for FileNotFoundException and log a warning rather than crashing","For library operations, run a scan to synchronize the database with disk state before retrying"],"exampleFix":"// Defensive caller pattern:\n// try {\n//     directoryService.CopyFile(sourcePath, destPath);\n// } catch (FileNotFoundException ex) {\n//     logger.LogWarning(ex, \"Source file vanished before copy: {Path}\", sourcePath);\n//     // handle gracefully — skip or re-scan\n// }","handlingStrategy":"try-catch","validationCode":"// Check file existence before copying:\n// if (!File.Exists(sourcePath)) {\n//     logger.LogWarning(\"Source file not found: {Path}\", sourcePath);\n//     return false;\n// }","typeGuard":null,"tryCatchPattern":"// try {\n//     directoryService.CopyFile(sourcePath, destinationPath, overwrite);\n// } catch (FileNotFoundException ex) {\n//     logger.LogWarning(ex, \"Source file vanished before copy: {Path}\", ex.FileName);\n//     // handle gracefully — skip, re-scan, or report media issue\n// }","preventionTips":["Validate file existence immediately before copy operations, not just at enumeration time","Avoid concurrent file operations from external tools on the library directory","Wrap copy operations in try-catch for FileNotFoundException and report missing files as MediaIssues"],"tags":["filesystem","file","not-found","io","race-condition"],"backgroundTag":null,"analyzedSha":"9c3e5400007f8a0282f7d883f2ad5e71716e514d","analyzedAt":"2026-08-13T19:06:05.897Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}