{"record":{"id":"3e666c85bf7dc6bd","repo":"Kareadita/Kavita","slug":"cannot-copy-external-images","errorCode":null,"errorMessage":"Cannot copy external images","messagePattern":"Cannot copy external images","errorType":"exception","errorClass":"KavitaException","httpStatus":null,"severity":"warning","filePath":"Kavita.Services/BookService.cs","lineNumber":1279,"sourceCode":"            var targetImage = images[bookmarkDto.ImageOffset];\n\n            // Get the image source attribute\n            var srcAttributeName = GetImageSrcAttributeName(targetImage);\n\n            if (string.IsNullOrEmpty(srcAttributeName))\n            {\n                throw new KavitaException(\"Image element does not have a valid source attribute\");\n            }\n\n            var imageSource = targetImage.Attributes[srcAttributeName].Value;\n\n            // Clean and get the correct key for the image\n            var imageKey = CleanContentKeys(GetKeyForImage(book, imageSource));\n\n            // Check if it's an external URL\n            if (imageKey.StartsWith(\"http\"))\n            {\n                throw new KavitaException(\"Cannot copy external images\");\n            }\n\n            // Get the image file from the epub\n\n            if (!book.Content.Images.TryGetLocalFileRefByKey(imageKey, out var imageFile))\n            {\n                throw new KavitaException($\"Image file not found in epub: {imageKey}\");\n            }\n\n            // Read the image content\n            var imageContent = await imageFile.ReadContentAsBytesAsync();\n\n            // Determine file extension from the image key or content type\n            var extension = Path.GetExtension(imageKey);\n            if (string.IsNullOrEmpty(extension))\n            {\n                // Fallback to determining extension from content type\n                extension = imageFile.ContentType switch","sourceCodeStart":1261,"sourceCodeEnd":1297,"githubUrl":"https://github.com/Kareadita/Kavita/blob/9c3e5400007f8a0282f7d883f2ad5e71716e514d/Kavita.Services/BookService.cs#L1261-L1297","documentation":"Thrown by BookService.CopyImageToTempFromBook (line 1279) when the resolved image source key starts with 'http', i.e. the image is an external URL rather than an epub-internal resource. Kavita cannot (and will not) fetch remote images during image copy.","triggerScenarios":"Bookmark/copy-image request on a page whose <img src> is an absolute http(s) URL to a remote server rather than a path inside the epub.","commonSituations":"Epubs that hot-link cover art or illustrations from a publisher CDN; DRM/preview epubs with remote-only images.","solutions":["Re-package the epub to embed the image as an internal resource instead of an external URL.","On the client, disable copy-image for pages known to reference remote images."],"exampleFix":"// before\nif (imageKey.StartsWith(\"http\"))\n    throw new KavitaException(\"Cannot copy external images\");\n\n// caller — pre-check the image source scheme\nif (Uri.TryCreate(imageSrc, UriKind.Absolute, out var u) && u.Scheme.StartsWith(\"http\"))\n    return BadRequest(\"External images cannot be copied\");","handlingStrategy":"validation","validationCode":"// Reject external-image pages before requesting copy\nif (Uri.TryCreate(src, UriKind.Absolute, out var u) && (u.Scheme == \"http\" || u.Scheme == \"https\"))\n    return BadRequest(\"External images cannot be copied\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Re-package epubs to embed images internally rather than hot-linking URLs.","On the client, detect remote src and disable copy-image."],"tags":["book-reader","epub","bookmark","validation","external-resource"],"backgroundTag":null,"analyzedSha":"9c3e5400007f8a0282f7d883f2ad5e71716e514d","analyzedAt":"2026-08-13T19:06:05.897Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}