{"record":{"id":"145f57e22bbdec56","repo":"BookStackApp/BookStack","slug":"errors-image-upload-replace-type","errorCode":null,"errorMessage":"errors.image_upload_replace_type","messagePattern":"errors\\.image_upload_replace_type","errorType":"exception","errorClass":"ImageUploadException","httpStatus":null,"severity":"warning","filePath":"app/Uploads/ImageRepo.php","lineNumber":183,"sourceCode":"     */\n    public function updateImageDetails(Image $image, $updateDetails): Image\n    {\n        $image->fill($updateDetails);\n        $image->updated_by = user()->id;\n        $image->save();\n        $this->imageResizer->loadGalleryThumbnailsForImage($image, false);\n\n        return $image;\n    }\n\n    /**\n     * Update the image file of an existing image in the system.\n     * @throws ImageUploadException\n     */\n    public function updateImageFile(Image $image, UploadedFile $file): void\n    {\n        if (strtolower($file->getClientOriginalExtension()) !== strtolower(pathinfo($image->path, PATHINFO_EXTENSION))) {\n            throw new ImageUploadException(trans('errors.image_upload_replace_type'));\n        }\n\n        $image->refresh();\n        $image->updated_by = user()->id;\n        $image->touch();\n        $image->save();\n\n        $this->imageService->replaceExistingFromUpload($image->path, $image->type, $file);\n        $this->imageResizer->loadGalleryThumbnailsForImage($image, true);\n    }\n\n    /**\n     * Destroys an Image object along with its revisions, files and thumbnails.\n     *\n     * @throws Exception\n     */\n    public function destroyImage(?Image $image = null): void\n    {","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/BookStackApp/BookStack/blob/18f8469a1c72f8cc8497e9372635e6dea5028071/app/Uploads/ImageRepo.php#L165-L201","documentation":"ImageUploadException with 'errors.image_upload_replace_type' is thrown by ImageRepo::updateImageFile when the extension of the replacement uploaded file does not match the extension of the existing image record's stored path. BookStack forbids replacing an image with a different file type (e.g. swapping a .png for a .jpg) to keep stored data consistent.","triggerScenarios":"Calling updateImageFile($image, $file) where strtolower($file->getClientOriginalExtension()) !== strtolower(pathinfo($image->path, PATHINFO_EXTENSION)) — i.e. uploading a JPEG to replace a PNG record, or vice versa.","commonSituations":"Users replacing a gallery/cover image via the image manager UI with a different-format file; automated uploads using the API image replace endpoint with a differently-typed file; case mismatch is handled (lowercased) so only true type differences trigger it.","solutions":["Upload a replacement file with the same extension as the original image","Alternatively delete the existing image and upload the new one as a fresh image","Check $image->path extension first and convert/normalize the new file client-side before replacing"],"exampleFix":"// before\n$repo->updateImageFile($image, $jpegFile); // image.path is foo.png\n// after\nif (strtolower($jpegFile->getClientOriginalExtension()) === strtolower(pathinfo($image->path, PATHINFO_EXTENSION))) {\n    $repo->updateImageFile($image, $jpegFile);\n} else {\n    $repo->destroyImage($image);\n    $repo->saveNew($jpegFile, 'foo.jpg', $galleryId);\n}","handlingStrategy":"validation","validationCode":"$existingExt = strtolower(pathinfo($image->path, PATHINFO_EXTENSION));\n$newExt = strtolower($file->getClientOriginalExtension());\nif ($existingExt !== $newExt) {\n    return back()->withErrors([\"Replacement must be .$existingExt to match the original image.\"]);\n}","typeGuard":null,"tryCatchPattern":"try {\n    $imageRepo->updateImageFile($image, $file);\n} catch (ImageUploadException $e) {\n    return back()->withErrors(['image' => 'File type must match the original image extension.']);\n}","preventionTips":["Compare the replacement file's extension with the existing image path's extension before calling updateImageFile","Offer users a delete-then-upload flow instead of replace when formats differ","Normalize/convert uploaded images to the original format server-side before replacing","Restrict the file input's accept attribute to the original image's MIME type in the UI"],"tags":["php","laravel","image-upload","validation","file-type"],"backgroundTag":"file-type-mismatch","analyzedSha":"18f8469a1c72f8cc8497e9372635e6dea5028071","analyzedAt":"2026-09-02T19:49:33.068Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}