{"record":{"id":"32222e8257749e1a","repo":"phalcon/cphalcon","slug":"router-cache-is-missing-routes-field","errorCode":null,"errorMessage":"Router cache is missing 'routes' field","messagePattern":"Router cache is missing 'routes' field","errorType":"exception","errorClass":"Phalcon\\Mvc\\Router\\Exception","httpStatus":null,"severity":"error","filePath":"phalcon/Mvc/Router.zep","lineNumber":835,"sourceCode":"            convName, converter, rebuiltRoutes, methodRoutesRehydrated,\n            candidatesRehydrated, staticRehydrated, innerKey, innerVal,\n            scalarIdx, scalarSubKey, mostInnerVal, mostInnerArr;\n        int dumpVersion;\n\n        if !isset dump[\"version\"] {\n            throw new Exception(\"Router cache is missing 'version' field\");\n        }\n\n        let dumpVersion = (int) dump[\"version\"];\n\n        if dumpVersion !== 1 {\n            throw new Exception(\n                \"Router cache version \" . dumpVersion . \" is not supported (this build supports version 1)\"\n            );\n        }\n\n        if !isset dump[\"routes\"] {\n            throw new Exception(\"Router cache is missing 'routes' field\");\n        }\n\n        let rebuiltRoutes = [];\n\n        for routeData in dump[\"routes\"] {\n            let routeClass = routeData[\"class\"];\n            let route      = new {routeClass}(routeData[\"pattern\"], routeData[\"paths\"], routeData[\"methods\"]);\n\n            if routeData[\"hostname\"] !== null {\n                route->setHostname(routeData[\"hostname\"]);\n            }\n\n            if routeData[\"name\"] !== null {\n                route->setName(routeData[\"name\"]);\n            }\n\n            route->setRouteId(routeData[\"id\"]);\n","sourceCodeStart":817,"sourceCodeEnd":853,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Mvc/Router.zep#L817-L853","documentation":"After the version check, loadDispatcherFromArray() requires a 'routes' key holding the array of serialized route definitions. Its absence means the dump is structurally invalid - truncated, hand-written, or produced by something other than buildDispatcherDump(). The loader never guesses defaults; both 'version' and 'routes' must be present and consistent.","triggerScenarios":"Passing an array that has 'version' => 1 but no 'routes' (hand-crafted or partially built); a cache file whose var_export output was cut off after the header; a cache entry that was overwritten by another structure that happens to contain a 'version' key.","commonSituations":"Hand-rolled 'optimized' route caches that mimic the format but omit fields; corrupt cache files from interrupted writes; cache-store key collisions with application data that also uses a 'version' field; test fixtures with minimal arrays passed straight to the loader.","solutions":["Regenerate the dump with dumpDispatcher()/buildDispatcherDump() so 'routes' is populated by the dumper itself","Clear the offending cache file/key and let the cold path rebuild it","Pre-validate structure before loading: isset($dump['version'], $dump['routes']) and is_array($dump['routes'])","Give the router cache a dedicated, unique key/path so unrelated data cannot collide with it"],"exampleFix":"// before\n$router->loadDispatcher($path); // dump missing 'routes' -> throws\n\n// after: validate then rebuild on any structural miss\n$dump = is_file($path) ? require $path : null;\nif (!is_array($dump) || !isset($dump['version'], $dump['routes'])) {\n    buildRoutes($router)->dumpDispatcher($path); // regenerate\n    $dump = require $path;\n}\n$router->loadDispatcherFromArray($dump);","handlingStrategy":"validation","validationCode":"$dump = is_file($path) ? require $path : null;\nif (!is_array($dump) || !isset($dump['routes']) || !is_array($dump['routes'])) {\n    buildRoutes($router)->dumpDispatcher($path); // regenerate valid structure\n    $dump = require $path;\n}\n$router->loadDispatcherFromArray($dump);","typeGuard":"function isRouterDumpShape(mixed $dump): bool\n{\n    return is_array($dump)\n        && isset($dump['version'], $dump['routes'])\n        && is_array($dump['routes']);\n}","tryCatchPattern":"try {\n    $router->loadDispatcher($path);\n} catch (\\Phalcon\\Mvc\\Router\\Exception $e) {\n    @unlink($path);\n    buildRoutes($router)->dumpDispatcher($path);\n    $router->loadDispatcher($path);\n}","preventionTips":["Regenerate caches from code, never patch generated files by hand","Validate both 'version' and 'routes' presence in a shared loader helper","Atomic writes (the dumper's tmp+rename) only help if nothing else writes to the path - keep it exclusive"],"tags":["phalcon","router","caching","cache-validation"],"backgroundTag":"cache-schema-mismatch","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}