BookStackApp/BookStack · error · PrettyException
Invalid non-image file type when streaming from storage
Error message
Invalid non-image file type when streaming from storage
What it means
A PrettyException (HTTP 415) is thrown by ImageService::streamImageFromStorageResponse when the Content-Type of the streamed storage response does not start with 'image/'. This is a safety check ensuring only actual image files are streamed inline from storage, guarding against serving stored non-image or mislabeled files.
Source
Thrown at app/Uploads/ImageService.php:380
return false;
}
/**
* For the given path, if existing, provide a response that will stream the image contents.
*/
public function streamImageFromStorageResponse(string $imageType, string $path): StreamedResponse
{
$disk = $this->storage->getDisk($imageType);
$stream = $disk->stream($path);
$fileSize = $disk->size($path);
$imageName = basename($path);
$downloadResponseFactory = new DownloadResponseFactory(request());
$response = $downloadResponseFactory->streamedInline($stream, $imageName, $fileSize);
$contentType = $response->headers->get('Content-Type');
if (!str_starts_with($contentType, 'image/')) {
throw new PrettyException('Invalid non-image file type when streaming from storage', 415);
}
return $response;
}
/**
* Check if the given image extension is supported by BookStack.
* The extension must not be altered in this function. This check should provide a guarantee
* that the provided extension is safe to use for the image to be saved.
*/
public static function isExtensionSupported(string $extension): bool
{
return in_array(strtolower($extension), static::$supportedExtensions);
}
/**
* Get all mime-types for images formats which BookStack supports.
*/View on GitHub (pinned to 18f8469a1c)
Solutions
- Verify the file at the given path is a genuine image and re-upload it if corrupt or replaced
- Delete the bad image record/file and upload the correct image via the UI or API
- Check whether an intermediary/proxy is rewriting the Content-Type header
- Use file (Linux) or getimagesize() to confirm the stored file's actual type
Example fix
// before: manually copied files into uploads $ cp /tmp/notes.txt storage/app/uploads/images/gallery/notes.png // after: upload via API/UI so type is validated $ curl -X POST /api/image-gallery -F 'file=@photo.png' -F 'name=photo'
Defensive patterns
Strategy: validation
Validate before calling
// verify before streaming
$mimeType = app('filesystem')->disk($diskName)->mimeType($path);
if ($mimeType === null || !str_starts_with($mimeType, 'image/')) {
abort(415, 'Requested file is not an image');
} Type guard
function isImageMime(?string $mime): bool
{
return $mime !== null && str_starts_with($mime, 'image/');
} Try / catch
try {
return $imageService->streamImageFromStorageResponse($diskName, $path);
} catch (PrettyException $e) {
abort(415, 'The requested file is not a valid image.');
} Prevention
- Only store validated image uploads under image paths (use the app's API/UI)
- Audit manually copied files in the storage directory for renamed non-images
- Do not place proxies/CDNs in front of storage that rewrite Content-Type headers
- Check mime type with getimagesize()/file before serving stored files inline
When it happens
Trigger: Calling streamImageFromStorageResponse($path) for a path whose stored file is not an image (wrong file stored under an image path), or where the mime-type detection returns a non-image type (e.g. application/octet-stream for unknown/corrupt files).
Common situations: Manually placed or renamed files in the uploads directory (e.g. a .txt renamed to .png) where the storage server reports a non-image content type; database image records pointing at files uploaded by other means; misconfigured storage proxies overriding Content-Type headers.
Related errors
- auth.email_confirm_send_error
- auth.registration_email_domain_invalid
- errors.path_not_writable
- errors.image_upload_replace_type
- errors.cannot_create_thumbs
AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02).
Data as JSON: /api/errors/f5415c06a373442f.
Report an issue: GitHub.