Kavita is a fast, feature rich, cross platform reading server. Built with the goal of being a full solution for all your reading needs. Setup your own server and share your reading collection with your friends and family.
Kavita fails to access files in folders added to libraries by UNC paths (e.g. \\Server\Share\Directory\File), so series in those folders cannot be discovered during library scans.
The problem is two-fold:
A. Web UI applies incorrect path normalization before sending API request
This truncates leading \\ into \, so UNC path \\Server\Share\Directory\File becomes \Server\Share\Directory\File, which is then sent to the backend. The latter is no longer a UNC path and will be interpreted as a relative path instead.
Entering the UNC path with forward slashes (//Server/Share/Directory/File, uncanonical) avoids the truncation and works around this problem, which brings us to:
B. Backend applies incorrect path normalization during library scan
/// <summary>
/// Normalizes the slashes in a path to be <see cref="Path.AltDirectorySeparatorChar"/>
/// </summary>
/// <example>/manga/1\1 -> /manga/1/1</example>
/// <param name="path"></param>
/// <returns></returns>
public static string NormalizePath(string? path)
{
return string.IsNullOrEmpty(path) ? string.Empty : path.Replace('\\', Path.AltDirectorySeparatorChar)
.Replace(@"//", Path.AltDirectorySeparatorChar + string.Empty);
}
Any double forward slashes will be combines into one. So //Server/Share/Directory/File would be normalized into /Server/Share/Directory/File. This is again interpreted as a relative path, and upon file access the .NET BCL will expand it into an absolute path based on the application's current drive, which by default is the drive where the application's executable file is located. For example, if kavita.exe is located at C:\Kavita\kavita.exe, the actual file Kavita tries to access will be C:/Server/Share/Directory/File. Such files most probably do not exist, so access will fail.
Removing the second Replace() call solves the problem for me, so I believe the changes required to address those problems should be trivial, and I'm glad to make such contributions. However, seeing it as a potentially breaking change, and that there are tests for this specific behavior, I would really like to have a discussion first in order to know more background for those decisions.
What did you expect?
There should be end-to-end support for UNC paths, so users can add folders hosted on remote file shares to their libraries.
Kavita Version Number - If you don not see your version number listed, please update Kavita and see if your issue still persists.
0.8.1 - Stable
What operating system is Kavita being hosted from?
Windows
If the issue is being seen on Desktop, what OS are you running where you see the issue?
None
If the issue is being seen in the UI, what browsers are you seeing the problem on?
No response
If the issue is being seen on Mobile, what OS are you running where you see the issue?
None
If the issue is being seen on the Mobile UI, what browsers are you seeing the problem on?
No response
Relevant log output
[Kavita] [2024-04-24 12:15:32.657 -07:00 91] [Information] API.Services.TaskScheduler Enqueuing library scan for: 5
[Kavita] [2024-04-24 12:15:32.660 -07:00 91] [Information] Serilog.AspNetCore.RequestLoggingMiddleware HTTP POST /api/library/scan?libraryId=5&force=true responded 200 in 5.5382 ms
[Kavita] [2024-04-24 12:15:32.661 -07:00 18] [Information] API.Services.Tasks.CleanupService Performing cleanup of Cache directories
[Kavita] [2024-04-24 12:15:32.662 -07:00 18] [Information] API.Services.Tasks.CleanupService Cache directory purged
[Kavita] [2024-04-24 12:15:32.665 -07:00 89] [Information] API.Services.Tasks.ScannerService [ScannerService] Beginning file scan on Manga
[Kavita] [2024-04-24 12:15:32.675 -07:00 89] [Debug] API.Services.Tasks.ScannerService [ScannerService] Found 11 files for //Media/Manga/Test\Nichijou
[Kavita] [2024-04-24 12:15:33.136 -07:00 89] [Information] API.Services.Tasks.Scanner.ProcessSeries [ScannerService] Beginning series update on Nichijou, Forced: true
[Kavita] [2024-04-24 12:15:33.140 -07:00 89] [Information] API.Services.Tasks.Scanner.ProcessSeries [ScannerService] Processing series Nichijou
[Kavita] [2024-04-24 12:15:33.140 -07:00 89] [Debug] API.Services.Tasks.Scanner.ProcessSeries [ScannerService] Updating 11 volumes on Nichijou
[Kavita] [2024-04-24 12:15:33.140 -07:00 89] [Debug] API.Services.Tasks.Scanner.ProcessSeries [ScannerService] Parsing Nichijou - Volume 1
[Kavita] [2024-04-24 12:15:33.141 -07:00 89] [Debug] API.Services.Tasks.Scanner.ProcessSeries [ScannerService] Adding new chapter, Nichijou - Vol 1 Ch -100000
[Kavita] [2024-04-24 12:15:33.141 -07:00 89] [Warning] API.Services.ArchiveService Archive /Media/Manga/Test/Nichijou/Nichijou v01 (2016) (Digital) (1r0n).cbz could not be found
[Kavita] [2024-04-24 12:15:33.141 -07:00 89] [Error] API.Services.ArchiveService Archive /Media/Manga/Test/Nichijou/Nichijou v01 (2016) (Digital) (1r0n).cbz could not be found
[Kavita] [2024-04-24 12:15:33.142 -07:00 89] [Error] API.Services.Tasks.Scanner.ProcessSeries [ScannerService] There was an exception updating series for Nichijou
System.IO.FileNotFoundException: Could not find file 'C:\Media\Manga\Test\Nichijou\Nichijou v01 (2016) (Digital) (1r0n).cbz'.
File name: 'C:\Media\Manga\Test\Nichijou\Nichijou v01 (2016) (Digital) (1r0n).cbz'
at System.IO.FileInfo.get_Length()
at System.IO.Abstractions.FileInfoWrapper.get_Length()
at API.Services.Tasks.Scanner.ProcessSeries.AddOrUpdateFileForChapter(Chapter chapter, ParserInfo info, Boolean forceUpdate) in C:\Users\josep\Documents\Projects\KavitaOrg\Kavita\API\Services\Tasks\Scanner\ProcessSeries.cs:line 757
at API.Services.Tasks.Scanner.ProcessSeries.UpdateChapters(Series series, Volume volume, IList`1 parsedInfos, Boolean forceUpdate) in C:\Users\josep\Documents\Projects\KavitaOrg\Kavita\API\Services\Tasks\Scanner\ProcessSeries.cs:line 702
at API.Services.Tasks.Scanner.ProcessSeries.UpdateVolumes(Series series, IList`1 parsedInfos, Boolean forceUpdate) in C:\Users\josep\Documents\Projects\KavitaOrg\Kavita\API\Services\Tasks\Scanner\ProcessSeries.cs:line 619
at API.Services.Tasks.Scanner.ProcessSeries.ProcessSeriesAsync(IList`1 parsedInfos, Library library, Boolean forceUpdate) in C:\Users\josep\Documents\Projects\KavitaOrg\Kavita\API\Services\Tasks\Scanner\ProcessSeries.cs:line 148
[Kavita] [2024-04-24 12:15:33.143 -07:00 89] [Information] API.Services.Tasks.ScannerService [ScannerService] Finished file scan in 465 milliseconds. Updating database
[Kavita] [2024-04-24 12:15:33.171 -07:00 89] [Information] API.Services.Tasks.ScannerService [ScannerService] Finished library scan of 11 files and 1 series in 510 milliseconds for Manga
[Kavita] [2024-04-24 12:15:33.171 -07:00 89] [Debug] API.Services.Tasks.ScannerService [ScannerService] Removing Series that were not found during the scan
[Kavita] [2024-04-24 12:15:33.172 -07:00 86] [Debug] API.Controllers.LibraryController Caching libraries for library_DL444
[Kavita] [2024-04-24 12:15:33.173 -07:00 89] [Debug] API.Services.Tasks.ScannerService [ScannerService] Found 1 series that needs to be removed: ["Nichijou"]
[Kavita] [2024-04-24 12:15:33.173 -07:00 89] [Debug] API.Services.Tasks.ScannerService [ScannerService] Removing Series that were not found during the scan - complete
Additional Notes
One workaround is to map the file shares to drive letters and access the files by them. This should be trivial for interactive workstation deployments but can be more involved for headless server deployments using Windows service wrappers.
Some service wrapper implementations provide features to facilitate this. For example, WinSW seems to support this scenario. However, I don't see any information on this for Shawl, so the workaround might not always be available.
What happened?
Kavita fails to access files in folders added to libraries by UNC paths (e.g.
\\Server\Share\Directory\File
), so series in those folders cannot be discovered during library scans.The problem is two-fold:
A. Web UI applies incorrect path normalization before sending API request
At library-settings-modal.components.ts:286 and :297:
This truncates leading
\\
into\
, so UNC path\\Server\Share\Directory\File
becomes\Server\Share\Directory\File
, which is then sent to the backend. The latter is no longer a UNC path and will be interpreted as a relative path instead.Entering the UNC path with forward slashes (
//Server/Share/Directory/File
, uncanonical) avoids the truncation and works around this problem, which brings us to:B. Backend applies incorrect path normalization during library scan
At Parser.cs:1190:
Any double forward slashes will be combines into one. So
//Server/Share/Directory/File
would be normalized into/Server/Share/Directory/File
. This is again interpreted as a relative path, and upon file access the .NET BCL will expand it into an absolute path based on the application's current drive, which by default is the drive where the application's executable file is located. For example, ifkavita.exe
is located atC:\Kavita\kavita.exe
, the actual file Kavita tries to access will beC:/Server/Share/Directory/File
. Such files most probably do not exist, so access will fail.Removing the second
Replace()
call solves the problem for me, so I believe the changes required to address those problems should be trivial, and I'm glad to make such contributions. However, seeing it as a potentially breaking change, and that there are tests for this specific behavior, I would really like to have a discussion first in order to know more background for those decisions.What did you expect?
There should be end-to-end support for UNC paths, so users can add folders hosted on remote file shares to their libraries.
Kavita Version Number - If you don not see your version number listed, please update Kavita and see if your issue still persists.
0.8.1 - Stable
What operating system is Kavita being hosted from?
Windows
If the issue is being seen on Desktop, what OS are you running where you see the issue?
None
If the issue is being seen in the UI, what browsers are you seeing the problem on?
No response
If the issue is being seen on Mobile, what OS are you running where you see the issue?
None
If the issue is being seen on the Mobile UI, what browsers are you seeing the problem on?
No response
Relevant log output
Additional Notes
One workaround is to map the file shares to drive letters and access the files by them. This should be trivial for interactive workstation deployments but can be more involved for headless server deployments using Windows service wrappers.
Some service wrapper implementations provide features to facilitate this. For example, WinSW seems to support this scenario. However, I don't see any information on this for Shawl, so the workaround might not always be available.