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

  1. Delete the route cache file (e.g. rm var/cache/routes.php) so it is regenerated from the current definitions, then reload
  2. Add cache invalidation to the deploy pipeline: clear the route cache whenever any route definition file changes
  3. Make route registration deterministic — never register routes conditionally on environment/debug flags while caching is enabled
  4. 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

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


AI-assisted analysis of slimphp/Slim@80900fb39c (2026-08-21). Data as JSON: /api/errors/847f8361a4e79def. Report an issue: GitHub.