Kareadita/Kavita · error · KavitaException
Path not found in CBL repository: {path}
Error message
Path not found in CBL repository: {path} What it means
Thrown in CblGithubService's 404 handler after FetchDirectoryFromGithub gets a FlurlHttpException with StatusCode 404. It means the GitHub contents API could not find the requested path in the DieselTech/CBL-ReadingLists repository - either the path never existed, was renamed/moved, or the leading-slash normalization produced a wrong key.
Source
Thrown at Kavita.Services/ReadingLists/CblGithubService.cs:225
if (rateLimit.IsExhausted)
{
var resetsIn = rateLimit.ResetsAtUtc.HasValue
? $" Resets at {rateLimit.ResetsAtUtc.Value:HH:mm} UTC."
: string.Empty;
_logger.LogWarning("GitHub API rate limit exhausted.{ResetsIn}", resetsIn);
throw new KavitaException(
$"GitHub API rate limit exhausted.{resetsIn} Cached data may still be available.");
}
_logger.LogWarning(ex, "GitHub API returned 403 for CBL repo");
throw new KavitaException("GitHub API access denied. Please try again later.");
}
catch (FlurlHttpException ex) when (ex.StatusCode == 404)
{
_logger.LogWarning("CBL repo path not found: {Path}", path.Sanitize());
throw new KavitaException($"Path not found in CBL repository: {path}");
}
}
private CblRepoCache LoadCache()
{
var cachePath = GetCacheFilePath();
if (!File.Exists(cachePath)) return new CblRepoCache();
try
{
var json = File.ReadAllText(cachePath);
return JsonSerializer.Deserialize<CblRepoCache>(json) ?? new CblRepoCache();
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to read CBL repo cache, starting fresh");
return new CblRepoCache();
}View on GitHub (pinned to 9c3e540000)
Solutions
- Browse from the repo root and navigate to the correct path rather than deep-linking.
- Invalidate the local cache (InvalidateCache) so stale directory keys are dropped, then re-browse.
- Verify the exact path against the GitHub web UI for the DieselTech/CBL-ReadingLists repo.
- Re-check NormalizePath output for the input to ensure no segments are lost.
Example fix
// before
var content = await cblGithubService.GetFileContent("lists/old-name.cbl");
// after
cblGithubService.InvalidateCache();
var browse = await cblGithubService.BrowseRepo("lists");
var real = browse.Items.FirstOrDefault(i => i.Name.EndsWith(".cbl"))?.Path;
var content = real is null ? null : await cblGithubService.GetFileContent(real); Defensive patterns
Strategy: validation
Validate before calling
var browse = await cblGithubService.BrowseRepo(parentDir);
if (!browse.Items.Any(i => i.Path == filePath))
return NotFound($"Path {filePath} not found in CBL repo");
var content = await cblGithubService.GetFileContent(filePath); Type guard
static bool PathExistsInRepo(string path, IEnumerable<CblRepoItemDto> items) => items.Any(i => i.Path == path);
Try / catch
try { return await cblGithubService.GetFileContent(filePath); }
catch (KavitaException ex) when (ex.Message.Contains("Path not found"))
{ cblGithubService.InvalidateCache(); return NotFound(ex.Message); } Prevention
- Browse from root instead of deep-linking stale paths.
- Invalidate cache after repo restructures.
- Validate path existence via BrowseRepo before GetFileContent.
When it happens
Trigger: Browsing or fetching a file/dir path that does not exist in the CBL repo: a stale cached path after the repo was restructured, a user-typed path with a typo, or NormalizePath stripping a needed segment.
Common situations: The upstream CBL repo renamed/moved directories; a user copy-pasted an old link; NormalizePath collapsed './' or trailing slash in a way that mismatches the API; or forceRefresh bypassed a still-valid cache entry pointing at a deleted folder.
Related errors
- library-doesnt-exist
- profile-does-not-exist
- No download URL available for {filePath}
- GitHub API rate limit exhausted.{resetsIn} Cached data may s
- GitHub API access denied. Please try again later.
AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13).
Data as JSON: /api/errors/3ab603291f7c55ee.
Report an issue: GitHub.