getgrav/grav · error · RuntimeException
500
500
Error message
Not Implemented
What it means
MediaObject::createResponse() turns a media object into an HTTP response after applying medium actions (resize etc.). The source marks the limitation with a FIXME: the response path (filemtime/filesize/streaming with Content-Type, Last-Modified, ETag) is only implemented for ImageMedium instances. Any other medium (video, audio, PDF, or a media object whose file is missing) causes RuntimeException('Not Implemented', 500).
Source
Thrown at system/src/Grav/Framework/Media/MediaObject.php:125
*
* @param array $actions
* @return Response
*/
public function createResponse(array $actions): ResponseInterface
{
if (!isset($this->media)) {
return $this->create404Response($actions);
}
$media = $this->media;
if ($actions) {
$media = $this->processMediaActions($media, $actions);
}
// FIXME: This only works for images
if (!$media instanceof ImageMedium) {
throw new \RuntimeException('Not Implemented', 500);
}
$filename = $media->path(false);
$time = filemtime($filename);
$size = filesize($filename);
$body = fopen($filename, 'rb');
$headers = [
'Content-Type' => $media->get('mime'),
'Last-Modified' => gmdate('D, d M Y H:i:s', $time) . ' GMT',
'ETag' => sprintf('%x-%x', $size, $time)
];
return new Response(200, $headers, $body);
}
/**
* Process media actions
*View on GitHub (pinned to 6040efed04)
Solutions
- Before triggering the response path, branch on the medium type and only use createResponse() for images (instanceof ImageMedium / getMime starting with 'image/').
- For non-image files, serve the original file or link directly (e.g. $media->url()) instead of the actions/response pipeline.
- If actions like resize are needed for videos, use ffmpeg-based or plugin-provided pipelines rather than Grav's image medium actions.
- Ensure the referenced file actually exists in the media folder so $this->media is set; otherwise you get the 404 branch instead of a broken response.
Example fix
// before
$response = $mediaObject->createResponse($actions); // video -> RuntimeException('Not Implemented', 500)
// after
$media = $mediaObject->getMedia();
if ($media instanceof \Grav\Common\Page\Medium\ImageMedium) {
$response = $mediaObject->createResponse($actions);
} else {
$response = new \Grav\Framework\Response($media ? $media->url() : '/fallback-file.png', 302);
} Defensive patterns
Strategy: type-guard
Validate before calling
$media = $mediaObject->getMedia();
if ($media instanceof \Grav\Common\Page\Medium\ImageMedium) {
$response = $mediaObject->createResponse($actions);
} else {
// non-image: serve original or redirect
$response = $media ? $media->url() : null;
} Type guard
function mediaSupportsActionResponse(\Grav\Framework\Media\MediaObjectInterface $object): bool
{
$media = $object->getMedia();
return $media instanceof \Grav\Common\Page\Medium\ImageMedium;
} Try / catch
try {
$response = $mediaObject->createResponse($actions);
} catch (\RuntimeException $e) {
if ('Not Implemented' === $e->getMessage() && $e->getCode() === 500) {
// non-image medium: fall back to original file URL or 404
$response = $mediaObject->getMedia() ? $mediaObject->getMedia()->url() : '/404-not-found';
} else {
throw $e;
}
} Prevention
- Branch on instanceof ImageMedium (or mime type image/*) before using the actions/response pipeline.
- Restrict admin media fields that feed this API to image selections, or handle non-images with direct links.
- Test media routes with each file type (jpg, mp4, pdf) your site accepts.
When it happens
Trigger: Requesting a media URL that triggers actions/responses for a non-image file, e.g. a video or PDF passed through a route that calls createResponse(); applying image-style actions to a non-image medium and then rendering the response; the media field resolving to a missing file so $this->media is unset for that type of flow combined with action parameters.
Common situations: Theme/template code reusing image-handling logic (thumbnails, resize filters) for arbitrary uploaded files; users uploading videos/PDFs into a media field that the template feeds into the media response API; upgrading Grav where such calls previously fell through to another code path.
Related errors
- Grav\Framework\Flex\Pages\Traits\PageLegacyTrait::init(): No
- Grav\Framework\Flex\Pages\Traits\PageLegacyTrait::raw(string
- Grav\Framework\Flex\Pages\Traits\PageLegacyTrait::file(): No
- Not Implemented
- Object has to be type %s, %s given
AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17).
Data as JSON: /api/errors/9de4ee6ad7b45ab8.
Report an issue: GitHub.