{"record":{"id":"9a4a1b720fc17ece","repo":"Kareadita/Kavita","slug":"page-bookmarkdto-page-not-found-in-epub","errorCode":null,"errorMessage":"Page {bookmarkDto.Page} not found in epub","messagePattern":"Page (.+?) not found in epub","errorType":"exception","errorClass":"KavitaException","httpStatus":null,"severity":"warning","filePath":"Kavita.Services/BookService.cs","lineNumber":1321,"sourceCode":"                    _ => \".png\"\n                };\n            }\n\n            // Create temp directory for this chapter if it doesn't exist\n            var tempChapterDir = Path.Combine(directoryService.TempDirectory, chapterId.ToString());\n            directoryService.ExistOrCreate(tempChapterDir);\n\n            // Generate unique filename\n            var uniqueFilename = $\"{Guid.NewGuid()}{extension}\";\n            var tempFilePath = Path.Combine(tempChapterDir, uniqueFilename);\n\n            // Write the image to the temp file\n            await File.WriteAllBytesAsync(tempFilePath, imageContent, ct);\n\n            return tempFilePath;\n        }\n\n        throw new KavitaException($\"Page {bookmarkDto.Page} not found in epub\");\n    }\n\n    private static string? GetImageSrcAttributeName(HtmlNode targetImage)\n    {\n        // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract\n        if (targetImage.Attributes[\"src\"] != null)\n        {\n            return \"src\";\n        }\n        // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract\n        if (targetImage.Attributes[\"xlink:href\"] != null)\n        {\n            return \"xlink:href\";\n        }\n\n        return null;\n    }\n","sourceCodeStart":1303,"sourceCodeEnd":1339,"githubUrl":"https://github.com/Kareadita/Kavita/blob/9c3e5400007f8a0282f7d883f2ad5e71716e514d/Kavita.Services/BookService.cs#L1303-L1339","documentation":"Thrown by BookService.CopyImageToTempFromBook (line 1321) after the reading-order loop completes without finding a page matching bookmarkDto.Page (and XHTML_1_1 content type). The requested page index is outside the epub's spine/reading order.","triggerScenarios":"Bookmark/copy-image request where bookmarkDto.Page is >= the number of XHTML pages in the reading order, or references a non-XHTML page (the loop only matches XHTML_1_1 pages with the right counter).","commonSituations":"Stale page index from a reader open on an older version of the epub; off-by-one (1-based vs 0-based) between client and the zero-based reading-order counter; page is an image/PDF-style non-XHTML entry.","solutions":["Validate bookmarkDto.Page against the epub's page count (0-based reading order) before calling.","Refresh book metadata on the client when the epub is re-scanned/replaced."],"exampleFix":"// before\nthrow new KavitaException($\"Page {bookmarkDto.Page} not found in epub\");\n\n// caller\nif (bookmarkDto.Page < 0 || bookmarkDto.Page >= totalPages) return BadRequest(\"Invalid page\");","handlingStrategy":"validation","validationCode":"// Validate page bounds before copy-image (0-based reading order)\nif (bookmarkDto.Page < 0 || bookmarkDto.Page >= totalPages)\n    return BadRequest(\"Invalid page\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use zero-based page indexing consistent with the epub reading order.","Refresh page count when the epub is re-scanned/replaced."],"tags":["book-reader","epub","bookmark","validation","index-out-of-range"],"backgroundTag":null,"analyzedSha":"9c3e5400007f8a0282f7d883f2ad5e71716e514d","analyzedAt":"2026-08-13T19:06:05.897Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}