Skip to content

[6.x] Guard ImageGenerator against a null asset - #15447

Open
wakqasahmed wants to merge 2 commits into
statamic:6.xfrom
wakqasahmed:fix/issue-15359-glide-null-asset
Open

[6.x] Guard ImageGenerator against a null asset#15447
wakqasahmed wants to merge 2 commits into
statamic:6.xfrom
wakqasahmed:fix/issue-15359-glide-null-asset

Conversation

@wakqasahmed

Copy link
Copy Markdown
Contributor

Closes #15359

ImageGenerator::generateByAsset() calls $asset->isVideo() immediately, so when an asset URL resolves to null (e.g. a repository that can't find the asset by that URL — statamic/eloquent-driver#609 is one real cause) it throws Error: Call to a member function isVideo() on null instead of returning gracefully. Because that's an \Error, not an \Exception, it isn't caught by the glide tag's existing catch (\Exception) handling, so one unresolvable asset 500s the whole page instead of just being skipped.

Added an early return of '' when $asset is falsy, matching the method's existing pattern of returning '' to skip (see the isVideo() branch just below it). Added a regression test for generateByAsset(null, [...]) and confirmed it throws the exact error from the issue before the fix and passes after. Ran the full tests/Imaging + tests/Tags/GlideTest.php suites (147 tests, 297 assertions) and Pint, both clean.

…c#15359)

When an asset URL resolves to null (e.g. a repository that can't
find the asset by that URL, such as statamic/eloquent-driver#609),
generateByAsset() dereferenced it directly, throwing an uncaught
Error rather than the Exception the glide tag already knows how to
catch and skip. Return '' early instead, matching the existing skip
convention used elsewhere in this method.
*/
public function generateByAsset($asset, array $params)
{
if (! $asset) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed the crash is real: Glide::generateImage() (src/Tags/Glide.php:180) does call generateByAsset(Asset::find($item), $params) unguarded, and Asset::find() can return null (e.g. when an item resolves as an asset ID/instance rather than a raw path, so it skips the Str::isUrl() branch and falls through to this line). So a null asset really can reach isVideo() here pre-fix — good catch, and the regression test faithfully reproduces the exact Error from the issue (fails pre-fix, passes post-fix).\n\nOne gap though: this silently returns '' with no Log::error() (or equivalent). The issue's own "Expected" behavior is "an asset that cannot be resolved is logged and skipped, like every other error inside the tag" — every other failure mode in Glide::generate()'s closure hits the catch (\Exception $e) { Log::error(...) } and gets logged. This new path is the one exception: it degrades gracefully but leaves zero trace, so the underlying "asset repository returned null for a resolvable file" condition (the actual bug, per statamic/eloquent-driver#609) becomes invisible/undebuggable in production — which is exactly the visibility gap that made the original 500 take a day to notice at scale.\n\nWorth considering: either add a Log::error()/Log::warning() call here before returning '', or (closer to the issue's first suggested alternative) guard in Glide::generateImage() by throwing an \Exception when Asset::find($item) is null, letting the tag's existing catch (\Exception) log it — that would also mean the 3 other callers of generateByAsset() (PresetGenerator, StaticUrlBuilder, ThumbnailController), which always pass an already-resolved asset, don't carry a defensive null-check they don't need. Not a blocker — the fix does stop the 500 — but as-is a real production trigger of this bug will still go unnoticed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair catch, added — Log::error() now fires before the early return (also rebased onto 6.x, which had picked up an unrelated conflicting change to this same method in the meantime).

@wakqasahmed wakqasahmed left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed cold against the linked issue and current source.

Verified as real: Glide::generateImage() (src/Tags/Glide.php:180) passes Asset::find($item) straight into generateByAsset() with no null check, and that result genuinely can be null (statamic/eloquent-driver#609 is a real, confirmed trigger). Pre-fix, generateByAsset() dereferences it immediately via isVideo(), throwing an uncaught \Error that isn't caught by the tag's catch (\Exception), so it does escalate one bad asset into a full-page 500. The fix (early return ''; before the first isVideo() call) stops that, and does so using the same sentinel ('') the method's own isVideo() skip-branch already returns, which Attributes::from() already handles gracefully (degrades to width/height 0, no crash). The new test in ImageGeneratorTest reproduces the exact issue error pre-fix and passes post-fix — traced through makeGenerator(), no mocking gaps.

One real gap (left as an inline comment on the added guard): the fix is silent — no Log::error() — where the issue explicitly asks for 'logged and skipped, like every other error inside the tag.' Every other failure path in Glide::generate()'s closure logs via its catch (\Exception); this one now uniquely doesn't, which reintroduces the original observability problem (undiagnosed for a day in production) in a quieter form. Suggest either logging here, or throwing in Glide::generateImage() instead so the existing catch handles it — that also avoids adding an unnecessary defensive check to generateByAsset()'s three other call sites (PresetGenerator, StaticUrlBuilder, ThumbnailController), which only ever pass already-resolved assets.

Also noting (not a code issue): GitHub currently reports this PR as CONFLICTING/DIRTY against 6.x — will need a rebase before merge.

Not blocking — the crash is genuinely fixed and the test is sound — but the logging gap is worth addressing before merge.

…null-asset

# Conflicts:
#	src/Imaging/ImageGenerator.php
#	tests/Imaging/ImageGeneratorTest.php
@jasonvarga jasonvarga changed the title Guard ImageGenerator against a null asset (#15359) Guard ImageGenerator against a null asset Sep 11, 2026
@duncanmcclean duncanmcclean changed the title Guard ImageGenerator against a null asset [6.x] Guard ImageGenerator against a null asset Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Glide tag 500s the whole page when an asset URL resolves to null (isVideo() on null)

1 participant