Bug description
@nocache throws a TypeError instead of rendering when the view is rendered outside a matched route.
Statamic\StaticCaching\NoCache\BladeDirective::handle() calls Cache::isBeingUsedOnCurrentRoute() on every render, and that method passes request()->route() straight into Router::gatherRouteMiddleware(), which typehints Route:
// src/StaticCaching/Middleware/Cache.php
public static function isBeingUsedOnCurrentRoute()
{
return in_array(static::class, app('router')->gatherRouteMiddleware(request()->route()));
}
When no route has matched, request()->route() is null and the typed parameter fatals.
The notable part is that BladeDirective already has the right behaviour for this case — it renders the region inline when static caching isn't active on the route:
if (! Cache::isBeingUsedOnCurrentRoute()) {
return view($view, $context)->render();
}
A routeless render is unambiguously "static caching is not active here", so this should take that fallback. Instead the check fatals before it can be reached, and a context that ought to degrade gracefully 500s.
The error message also points at static caching rather than at the real cause (a view rendered without a route), which makes it awkward to diagnose.
How to reproduce
- Add
resources/views/probe.blade.php containing <p>region</p>
- Render a
@nocache of it with no matched route — e.g. php artisan tinker:
config(['statamic.static_caching.strategy' => 'half']);
Blade::render('@nocache("probe")');
// TypeError
request()->setRouteResolver(fn () => new Illuminate\Routing\Route('GET', '/', fn () => ''));
Blade::render('@nocache("probe")');
// <p>region</p>
The first call throws; the second correctly takes the inline fallback.
How we hit it: a feature test that renders a Blade component tree containing a @nocache region via Blade::render(), with no HTTP request. The same applies to any non-HTTP render of page content (a PDF or email render, for instance).
Logs
Illuminate\Routing\Router::gatherRouteMiddleware(): Argument #1 ($route) must be of type
Illuminate\Routing\Route, null given, called in
vendor/statamic/cms/src/StaticCaching/Middleware/Cache.php on line 268
Environment
Statamic 6.27.2 Pro, Laravel 13.25.0, PHP 8.5.8, application static caching driver (half)
Installation
Existing Laravel app
Additional details
A null guard would make the existing fallback reachable:
public static function isBeingUsedOnCurrentRoute()
{
if (! $route = request()->route()) {
return false;
}
return in_array(static::class, app('router')->gatherRouteMiddleware($route));
}
Bug description
@nocachethrows aTypeErrorinstead of rendering when the view is rendered outside a matched route.Statamic\StaticCaching\NoCache\BladeDirective::handle()callsCache::isBeingUsedOnCurrentRoute()on every render, and that method passesrequest()->route()straight intoRouter::gatherRouteMiddleware(), which typehintsRoute:When no route has matched,
request()->route()isnulland the typed parameter fatals.The notable part is that
BladeDirectivealready has the right behaviour for this case — it renders the region inline when static caching isn't active on the route:A routeless render is unambiguously "static caching is not active here", so this should take that fallback. Instead the check fatals before it can be reached, and a context that ought to degrade gracefully 500s.
The error message also points at static caching rather than at the real cause (a view rendered without a route), which makes it awkward to diagnose.
How to reproduce
resources/views/probe.blade.phpcontaining<p>region</p>@nocacheof it with no matched route — e.g.php artisan tinker:The first call throws; the second correctly takes the inline fallback.
How we hit it: a feature test that renders a Blade component tree containing a
@nocacheregion viaBlade::render(), with no HTTP request. The same applies to any non-HTTP render of page content (a PDF or email render, for instance).Logs
Environment
Statamic 6.27.2 Pro, Laravel 13.25.0, PHP 8.5.8,
applicationstatic caching driver (half)Installation
Existing Laravel app
Additional details
A null guard would make the existing fallback reachable: