slimphp/Slim · critical · RuntimeException
Route not found, looks like your route cache is stale.
Error message
Route not found, looks like your route cache is stale.
What it means
During dispatch, RoutingMiddleware resolves the matched route identifier via RouteResolver->lookupRoute(), which searches only the in-memory $routes array of the live RouteCollector. When FastRoute reports FOUND but the identifier is missing in memory, it almost always means the dispatcher was built from a cached route set that no longer matches the routes actually registered in this process — hence the 'route cache is stale' message. It is a cache/definition desynchronization error, not a '404 the URL is wrong' error.
Source
Thrown at Slim/Routing/RouteCollector.php:222
}
foreach ($this->routes as $route) {
if ($name === $route->getName()) {
$this->routesByName[$name] = $route;
return $route;
}
}
throw new RuntimeException('Named route does not exist for name: ' . $name);
}
/**
* {@inheritdoc}
*/
public function lookupRoute(string $identifier): RouteInterface
{
if (!isset($this->routes[$identifier])) {
throw new RuntimeException('Route not found, looks like your route cache is stale.');
}
return $this->routes[$identifier];
}
/**
* {@inheritdoc}
*/
public function group(string $pattern, $callable): RouteGroupInterface
{
$routeGroup = $this->createGroup($pattern, $callable);
$this->routeGroups[] = $routeGroup;
$routeGroup->collectRoutes();
array_pop($this->routeGroups);
return $routeGroup;
}
View on GitHub (pinned to 80900fb39c)
Solutions
- Delete the route cache file (e.g. rm var/cache/routes.php) so it is regenerated from the current definitions, then reload
- Add cache invalidation to the deploy pipeline: clear the route cache whenever any route definition file changes
- Make route registration deterministic — never register routes conditionally on environment/debug flags while caching is enabled
- Give each app and each environment its own cache file; never commit or share route caches across releases
Example fix
// before
$cacheFile = __DIR__ . '/var/cache/routes.php';
$app->getRouteCollector()->setCacheFile($cacheFile); // cache from an older deploy, identifiers no longer match
// after — invalidate in bootstrap/deploy when definitions change
$cacheFile = __DIR__ . '/var/cache/routes.php';
if (file_exists($cacheFile) && filemtime($cacheFile) < filemtime(__DIR__ . '/config/routes.php')) {
unlink($cacheFile); // force regeneration from current definitions
}
$app->getRouteCollector()->setCacheFile($cacheFile); Defensive patterns
Strategy: fallback
Validate before calling
// bootstrap guard: drop the cache whenever any route definition source is newer
$cacheFile = __DIR__ . '/var/cache/routes.php';
$sources = glob(__DIR__ . '/config/routes/*.php');
if (file_exists($cacheFile)) {
$cacheAge = filemtime($cacheFile);
foreach ($sources as $src) {
if (filemtime($src) > $cacheAge) {
unlink($cacheFile);
break;
}
}
}
$app->getRouteCollector()->setCacheFile($cacheFile); Try / catch
try {
$response = $app->handle($request);
} catch (RuntimeException $e) {
if (str_contains($e->getMessage(), 'route cache is stale')) {
// one-shot recovery: drop the cache, force regeneration, retry once
@unlink($cacheFile);
$response = $app->handle($request);
} else {
throw $e;
}
} Prevention
- Treat the route cache as a build artifact: clear it in the same deploy step that ships route changes
- Never register routes conditionally (env/debug/tenant) when caching is enabled — one cache must fit all requests
- Give each app and environment a unique cache file path; exclude it from VCS and shared images
- Add a post-deploy health request (curl /) that would surface a stale cache before real users hit it
When it happens
Trigger: Enabling setCacheFile() and then changing, adding, or removing route definitions without deleting the cache file; registering routes conditionally (per environment, per debug flag, per tenant) so the cache was generated with a different set than the running process has; reusing a cache file committed to VCS or baked into a build artifact across code releases; two applications sharing one cache file.
Common situations: Deploy new code with an old routes.php cache left in cache/ from the previous build; a CI-built Docker image that copies a stale cache; routes defined inside if (env('DEBUG')) blocks so dev and prod need different caches; every request then throws this RuntimeException instead of serving the route, so the app appears hard-down after deploy.
Related errors
- Route collector cache file directory `%s` is not writable
- Named route does not exist for name: %s
- Cannot create RouteContext before routing has been completed
- No base path defined.
- Missing data for URL segment: %s
AI-assisted analysis of slimphp/Slim@80900fb39c (2026-08-21).
Data as JSON: /api/errors/847f8361a4e79def.
Report an issue: GitHub.