{"record":{"id":"2db48f2d216b7ed6","repo":"phalcon/cphalcon","slug":"failed-to-commit-router-cache-path","errorCode":null,"errorMessage":"Failed to commit router cache: {path}","messagePattern":"Failed to commit router cache: (.+?)","errorType":"exception","errorClass":"Phalcon\\Mvc\\Router\\Exception","httpStatus":null,"severity":"error","filePath":"phalcon/Mvc/Router.zep","lineNumber":937,"sourceCode":"     * dumps don't corrupt the result.\n     *\n     * @throws \\Phalcon\\Mvc\\Router\\Exception\n     */\n    public function dumpDispatcher( string path) -> void\n    {\n        var dump, php, tmpPath;\n\n        let dump    = this->buildDispatcherDump();\n        let php     = \"<?php\\nreturn \" . var_export(dump, true) . \";\\n\";\n        let tmpPath = path . \".tmp.\" . (string) getmypid();\n\n        if this->phpFilePutContents(tmpPath, php) === false {\n            throw new Exception(\"Failed to write router cache temp file: \" . tmpPath);\n        }\n\n        if !rename(tmpPath, path) {\n            this->phpUnlink(tmpPath);\n            throw new Exception(\"Failed to commit router cache: \" . path);\n        }\n    }\n\n    /**\n     * File-shaped helper around loadDispatcherFromArray(). Includes the\n     * file (opcache-friendly) and forwards the return value.\n     *\n     * @throws \\Phalcon\\Mvc\\Router\\Exception\n     */\n    public function loadDispatcher( string path) -> void\n    {\n        var dump;\n\n        if !this->phpFileExists(path) {\n            throw new Exception(\"Router cache not found: \" . path);\n        }\n\n        let dump = require path;","sourceCodeStart":919,"sourceCodeEnd":955,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Mvc/Router.zep#L919-L955","documentation":"After successfully writing the temp file, dumpDispatcher() commits the cache with rename(tmpPath, path). If rename fails it unlinks the temp file and throws 'Failed to commit router cache' with the target path. On POSIX this fails when the target directory lacks write/modify permission, the destination exists as a directory, or the filesystem rejects the operation; on Windows, an existing destination that is open/locked also fails.","triggerScenarios":"The target directory is writable enough to create the temp file but the final path is an existing read-only file owned by another user; path points at a directory; another process (editor, antivirus, opcache tool) holds the destination open on Windows; exotic mounts (some network/virtiofs filesystems) that do not support rename-over-existing.","commonSituations":"Cache file created by root during a manual deploy, then the web user cannot replace it; CI writing caches as one UID and the app runtime as another; stale cache file with 0444 perms; container volumes with unusual rename semantics.","solutions":["Delete the stale cache file and let the current writer recreate it: rm routes.php && re-run dump","Fix ownership/perms so the process calling dumpDispatcher() owns or may replace the target: chown phpuser routes.php / chmod 664 + dir 775","Verify path is a file path, not an existing directory","On Windows/shared mounts, ensure nothing holds the destination open; retry the dump after releasing locks"],"exampleFix":"// before\n$router->dumpDispatcher($path); // stale read-only file -> rename fails -> throws\n\n// after: remove unreplaceable artifacts before dumping\nif (is_file($path) && !is_writable($path)) {\n    if (!@unlink($path)) {\n        throw new RuntimeException(\"Cannot replace cache file: {$path}\");\n    }\n}\n$router->dumpDispatcher($path);\n\n# shell fix for ownership\n# chown www-data:www-data /var/www/app/cache/routes.php","handlingStrategy":"try-catch","validationCode":"// Ensure the dump can actually replace the target before calling dump\nif (is_file($path) && !is_writable($path)) {\n    if (!@unlink($path)) {\n        throw new RuntimeException(\"Cannot replace router cache file: {$path}\");\n    }\n}\nif (is_dir($path)) {\n    throw new RuntimeException(\"Router cache path is a directory: {$path}\");\n}\n$router->dumpDispatcher($path);","typeGuard":null,"tryCatchPattern":"try {\n    $router->dumpDispatcher($path);\n} catch (\\Phalcon\\Mvc\\Router\\Exception $e) {\n    // rename/commit failed: tmp file is already cleaned up by the router\n    $logger->error('Router cache commit failed: ' . $e->getMessage());\n    // app continues with runtime-built routes; alert ops to fix perms\n}","preventionTips":["Create cache files with the same UID/GID as the process that will rewrite them (or group-writable 664 + dir 775)","Never generate caches as root and serve as another user without chown","On Windows, close tools holding the destination file before re-dumping","Alert on repeated cache-commit failures instead of silently rebuilding routes forever"],"tags":["phalcon","router","caching","filesystem","rename","permissions"],"backgroundTag":"file-rename-failure","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}