slimphp/Slim · error · RuntimeException
Route collector cache file directory `%s` is not writable
Error message
Route collector cache file directory `%s` is not writable
What it means
Slim's RouteCollector::setCacheFile() validates the route-cache location when the app boots: if the cache file does not exist yet, the parent directory must be writable so FastRoute can create it. This RuntimeException is thrown when the file is absent and is_writable(dirname($cacheFile)) fails, meaning Slim cannot persist the compiled route table. It is a fail-fast configuration check that fires during App construction or the first setCacheFile() call, before any request is served.
Source
Thrown at Slim/Routing/RouteCollector.php:146
*/
public function getCacheFile(): ?string
{
return $this->cacheFile;
}
/**
* {@inheritdoc}
*/
public function setCacheFile(string $cacheFile): RouteCollectorInterface
{
if (file_exists($cacheFile) && !is_readable($cacheFile)) {
throw new RuntimeException(
sprintf('Route collector cache file `%s` is not readable', $cacheFile)
);
}
if (!file_exists($cacheFile) && !is_writable(dirname($cacheFile))) {
throw new RuntimeException(
sprintf('Route collector cache file directory `%s` is not writable', dirname($cacheFile))
);
}
$this->cacheFile = $cacheFile;
return $this;
}
/**
* {@inheritdoc}
*/
public function getBasePath(): string
{
return $this->basePath;
}
/**
* Set the base path used in urlFor()View on GitHub (pinned to 80900fb39c)
Solutions
- Use an absolute path built from the app root, e.g. __DIR__ . '/var/cache/routes.php', instead of a relative one
- Create the directory before enabling the cache: if (!is_dir($dir)) { mkdir($dir, 0775, true); }
- Grant write permission to the PHP process user: chown -R www-data var/cache or chmod 775, then verify with sudo -u www-data test -w var/cache
- If the directory is on a read-only mount (container), move the cache to a writable volume or disable route caching in that environment
Example fix
// before
$app = AppFactory::create();
$app->getRouteCollector()->setCacheFile('cache/routes.php'); // relative path, dir may not exist or not be writable
// after
$cacheDir = __DIR__ . '/var/cache';
if (!is_dir($cacheDir)) {
mkdir($cacheDir, 0775, true);
}
$app = AppFactory::create();
$app->getRouteCollector()->setCacheFile($cacheDir . '/routes.php'); Defensive patterns
Strategy: validation
Validate before calling
$cacheFile = __DIR__ . '/var/cache/routes.php';
$cacheDir = dirname($cacheFile);
if (!is_dir($cacheDir)) {
mkdir($cacheDir, 0775, true);
}
if (!is_writable($cacheDir)) {
throw new RuntimeException(
sprintf('Route cache dir %s not writable for user %s — fix before enabling cache', $cacheDir, get_current_user())
);
}
$app->getRouteCollector()->setCacheFile($cacheFile); Try / catch
try {
$app->getRouteCollector()->setCacheFile($cacheFile);
} catch (RuntimeException $e) {
// boot-time config failure: surface a clear ops message instead of a 500 on first request
$log->error($e->getMessage());
// optionally continue without cache in non-production: omit setCacheFile()
throw $e;
} Prevention
- Always build the cache path from __DIR__ or an env-injected absolute path, never a bare relative path
- Provision the cache directory in deployment scripts (mkdir -p) with ownership matching the PHP-FPM/Apache user
- Run a boot smoke test (e.g. a dep check command) that calls setCacheFile() and reports writability before traffic is routed to new code
- Document the cache location per environment so ops knows which volume must be writable
When it happens
Trigger: Calling $app->getRouteCollector()->setCacheFile($file) (or passing a 'routeCacheFile' setting / RouteCollector constructor argument) where $file does not exist and its directory is not writable for the PHP process user. Typical with a relative path like 'cache/routes.php' when the web-server cwd is public/, a never-created cache/ directory, or a directory owned by the deploy user while php-fpm/apache runs as www-data.
Common situations: Deployment where the cache directory was not created (mkdir missing from provisioning); Docker images with read-only volumes or multi-stage builds that drop the cache dir; CLI warm-up scripts run as root creating root-owned files/dirs that the web user cannot write to; SELinux or safe-mode restrictions blocking writes; relative paths that resolve differently between CLI and web contexts.
Related errors
- Route not found, looks like your route cache is stale.
- 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/5f98ac05825f9561.
Report an issue: GitHub.