{"record":{"id":"3ab603291f7c55ee","repo":"Kareadita/Kavita","slug":"path-not-found-in-cbl-repository-path","errorCode":null,"errorMessage":"Path not found in CBL repository: {path}","messagePattern":"Path not found in CBL repository: (.+?)","errorType":"exception","errorClass":"KavitaException","httpStatus":400,"severity":"error","filePath":"Kavita.Services/ReadingLists/CblGithubService.cs","lineNumber":225,"sourceCode":"\n            if (rateLimit.IsExhausted)\n            {\n                var resetsIn = rateLimit.ResetsAtUtc.HasValue\n                    ? $\" Resets at {rateLimit.ResetsAtUtc.Value:HH:mm} UTC.\"\n                    : string.Empty;\n\n                _logger.LogWarning(\"GitHub API rate limit exhausted.{ResetsIn}\", resetsIn);\n                throw new KavitaException(\n                    $\"GitHub API rate limit exhausted.{resetsIn} Cached data may still be available.\");\n            }\n\n            _logger.LogWarning(ex, \"GitHub API returned 403 for CBL repo\");\n            throw new KavitaException(\"GitHub API access denied. Please try again later.\");\n        }\n        catch (FlurlHttpException ex) when (ex.StatusCode == 404)\n        {\n            _logger.LogWarning(\"CBL repo path not found: {Path}\", path.Sanitize());\n            throw new KavitaException($\"Path not found in CBL repository: {path}\");\n        }\n    }\n\n    private CblRepoCache LoadCache()\n    {\n        var cachePath = GetCacheFilePath();\n        if (!File.Exists(cachePath)) return new CblRepoCache();\n\n        try\n        {\n            var json = File.ReadAllText(cachePath);\n            return JsonSerializer.Deserialize<CblRepoCache>(json) ?? new CblRepoCache();\n        }\n        catch (Exception ex)\n        {\n            _logger.LogWarning(ex, \"Failed to read CBL repo cache, starting fresh\");\n            return new CblRepoCache();\n        }","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/Kareadita/Kavita/blob/9c3e5400007f8a0282f7d883f2ad5e71716e514d/Kavita.Services/ReadingLists/CblGithubService.cs#L207-L243","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nvar content = await cblGithubService.GetFileContent(\"lists/old-name.cbl\");\n\n// after\ncblGithubService.InvalidateCache();\nvar browse = await cblGithubService.BrowseRepo(\"lists\");\nvar real = browse.Items.FirstOrDefault(i => i.Name.EndsWith(\".cbl\"))?.Path;\nvar content = real is null ? null : await cblGithubService.GetFileContent(real);","handlingStrategy":"validation","validationCode":"var browse = await cblGithubService.BrowseRepo(parentDir);\nif (!browse.Items.Any(i => i.Path == filePath))\n    return NotFound($\"Path {filePath} not found in CBL repo\");\nvar content = await cblGithubService.GetFileContent(filePath);","typeGuard":"static bool PathExistsInRepo(string path, IEnumerable<CblRepoItemDto> items) => items.Any(i => i.Path == path);","tryCatchPattern":"try { return await cblGithubService.GetFileContent(filePath); }\ncatch (KavitaException ex) when (ex.Message.Contains(\"Path not found\"))\n{ cblGithubService.InvalidateCache(); return NotFound(ex.Message); }","preventionTips":["Browse from root instead of deep-linking stale paths.","Invalidate cache after repo restructures.","Validate path existence via BrowseRepo before GetFileContent."],"tags":["github-api","cbl","not-found","validation"],"backgroundTag":null,"analyzedSha":"9c3e5400007f8a0282f7d883f2ad5e71716e514d","analyzedAt":"2026-08-13T19:06:05.897Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}