{"record":{"id":"5f98ac05825f9561","repo":"slimphp/Slim","slug":"route-collector-cache-file-directory-s-is-not-w","errorCode":null,"errorMessage":"Route collector cache file directory `%s` is not writable","messagePattern":"Route collector cache file directory `(.+?)` is not writable","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"Slim/Routing/RouteCollector.php","lineNumber":146,"sourceCode":"     */\n    public function getCacheFile(): ?string\n    {\n        return $this->cacheFile;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function setCacheFile(string $cacheFile): RouteCollectorInterface\n    {\n        if (file_exists($cacheFile) && !is_readable($cacheFile)) {\n            throw new RuntimeException(\n                sprintf('Route collector cache file `%s` is not readable', $cacheFile)\n            );\n        }\n\n        if (!file_exists($cacheFile) && !is_writable(dirname($cacheFile))) {\n            throw new RuntimeException(\n                sprintf('Route collector cache file directory `%s` is not writable', dirname($cacheFile))\n            );\n        }\n\n        $this->cacheFile = $cacheFile;\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function getBasePath(): string\n    {\n        return $this->basePath;\n    }\n\n    /**\n     * Set the base path used in urlFor()","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/slimphp/Slim/blob/80900fb39cafce3ae53b18a2c4f642a122f03095/Slim/Routing/RouteCollector.php#L128-L164","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n$app = AppFactory::create();\n$app->getRouteCollector()->setCacheFile('cache/routes.php'); // relative path, dir may not exist or not be writable\n\n// after\n$cacheDir = __DIR__ . '/var/cache';\nif (!is_dir($cacheDir)) {\n    mkdir($cacheDir, 0775, true);\n}\n$app = AppFactory::create();\n$app->getRouteCollector()->setCacheFile($cacheDir . '/routes.php');","handlingStrategy":"validation","validationCode":"$cacheFile = __DIR__ . '/var/cache/routes.php';\n$cacheDir = dirname($cacheFile);\nif (!is_dir($cacheDir)) {\n    mkdir($cacheDir, 0775, true);\n}\nif (!is_writable($cacheDir)) {\n    throw new RuntimeException(\n        sprintf('Route cache dir %s not writable for user %s — fix before enabling cache', $cacheDir, get_current_user())\n    );\n}\n$app->getRouteCollector()->setCacheFile($cacheFile);","typeGuard":null,"tryCatchPattern":"try {\n    $app->getRouteCollector()->setCacheFile($cacheFile);\n} catch (RuntimeException $e) {\n    // boot-time config failure: surface a clear ops message instead of a 500 on first request\n    $log->error($e->getMessage());\n    // optionally continue without cache in non-production: omit setCacheFile()\n    throw $e;\n}","preventionTips":["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"],"tags":["slim","php","routing","cache","filesystem","permissions"],"backgroundTag":"file-permission-denied","analyzedSha":"80900fb39cafce3ae53b18a2c4f642a122f03095","analyzedAt":"2026-08-21T01:41:09.580Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}