{"record":{"id":"4033ec5af597931a","repo":"phalcon/cphalcon","slug":"router-cache-value-at-key-key-is-not-an-array","errorCode":null,"errorMessage":"Router cache value at key '{key}' is not an array","messagePattern":"Router cache value at key '(.+?)' is not an array","errorType":"exception","errorClass":"Phalcon\\Mvc\\Router\\Exception","httpStatus":null,"severity":"error","filePath":"phalcon/Mvc/Router.zep","lineNumber":982,"sourceCode":"    }\n\n    /**\n     * Cache-instance convenience wrapper. On cache hit, restores the\n     * dispatcher immediately. On miss, defers cache population until the\n     * next handle() completes - at which point buildDispatcherDump() is\n     * written to the cache key.\n     *\n     * @throws \\Phalcon\\Mvc\\Router\\Exception\n     */\n    public function useCache(<CacheAdapterInterface> cache,  string key = \"phalcon.router.dispatcher\") -> void\n    {\n        var stored;\n\n        if cache->has(key) {\n            let stored = cache->get(key);\n\n            if typeof stored !== \"array\" {\n                throw new Exception(\n                    \"Router cache value at key '\" . key . \"' is not an array\"\n                );\n            }\n\n            this->loadDispatcherFromArray(stored);\n            return;\n        }\n\n        let this->pendingCache    = cache,\n            this->pendingCacheKey = key;\n    }\n\n    /**\n     * Returns the internal event manager\n     */\n    public function getEventsManager() -> <ManagerInterface> | null\n    {\n        return this->eventsManager;","sourceCodeStart":964,"sourceCodeEnd":1000,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Mvc/Router.zep#L964-L1000","documentation":"useCache(cache, key) restores the dispatcher from a Phalcon Cache adapter on hit. The stored value must be the array that buildDispatcherDump() produced; if the key holds anything else (a string, object, null coerced value), the router refuses it with this exception rather than attempting to rehydrate garbage routes.","triggerScenarios":"Calling useCache($cache, 'routes') when that key previously stored non-router data (rendered HTML, config objects, counters); two applications sharing one cache backend with colliding keys; a cache adapter whose get() returns an unexpected type after flush/serialization misconfiguration (e.g. serializer settings stripping arrays into strings).","commonSituations":"Key-reuse in a shared Redis/Memcached pool; a teammate 'pre-warmed' the key with the wrong payload; adapter serializer mismatch (serialize vs igbinary vs none) turning arrays into strings on read; renaming the router cache key but leaving old data under the new name's slot.","solutions":["Clear the offending key before enabling router caching: $cache->delete($key) (or flush the namespace), then let useCache()'s miss path populate it","Use a dedicated, namespaced key unique to this app and format: 'app:router:dispatcher:v1'","Verify adapter serializer settings round-trip arrays (set and get an array in a smoke test)","Pre-check the slot before wiring: if ($cache->has($key) && !is_array($cache->get($key))) $cache->delete($key);"],"exampleFix":"// before\n$router->useCache($cache, 'routes'); // 'routes' holds a serialized string -> throws\n\n// after: dedicated key + defensive cleanup\n$key = 'app01:router:dispatcher:v1';\nif ($cache->has($key) && !is_array($cache->get($key))) {\n    $cache->delete($key); // evict foreign/corrupt payload\n}\n$router->useCache($cache, $key);","handlingStrategy":"validation","validationCode":"// Evict a foreign payload before wiring the cache\nif ($cache->has($key) && !is_array($cache->get($key))) {\n    $cache->delete($key);\n}\n$router->useCache($cache, $key);","typeGuard":"function cacheSlotIsArray($cache, string $key): bool\n{\n    return !$cache->has($key) || is_array($cache->get($key));\n}","tryCatchPattern":"try {\n    $router->useCache($cache, $key);\n} catch (\\Phalcon\\Mvc\\Router\\Exception $e) {\n    $cache->delete($key);            // drop the bad payload\n    $router->useCache($cache, $key); // miss path will repopulate it\n}","preventionTips":["Use app-scoped, format-versioned cache keys ('app1:router:dispatcher:v1')","Smoke-test the adapter's serializer round-trip (set array, get array) during bootstrap","Never share one cache backend namespace between different data kinds without prefixes"],"tags":["phalcon","router","caching","cache-type-mismatch"],"backgroundTag":"cache-type-mismatch","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}