phalcon/cphalcon · error · Phalcon\Mvc\Router\Exception
Router cache value at key '{key}' is not an array
Error message
Router cache value at key '{key}' is not an array What it means
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.
Source
Thrown at phalcon/Mvc/Router.zep:982
}
/**
* Cache-instance convenience wrapper. On cache hit, restores the
* dispatcher immediately. On miss, defers cache population until the
* next handle() completes - at which point buildDispatcherDump() is
* written to the cache key.
*
* @throws \Phalcon\Mvc\Router\Exception
*/
public function useCache(<CacheAdapterInterface> cache, string key = "phalcon.router.dispatcher") -> void
{
var stored;
if cache->has(key) {
let stored = cache->get(key);
if typeof stored !== "array" {
throw new Exception(
"Router cache value at key '" . key . "' is not an array"
);
}
this->loadDispatcherFromArray(stored);
return;
}
let this->pendingCache = cache,
this->pendingCacheKey = key;
}
/**
* Returns the internal event manager
*/
public function getEventsManager() -> <ManagerInterface> | null
{
return this->eventsManager;View on GitHub (pinned to b7419de9cd)
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);
Example fix
// before
$router->useCache($cache, 'routes'); // 'routes' holds a serialized string -> throws
// after: dedicated key + defensive cleanup
$key = 'app01:router:dispatcher:v1';
if ($cache->has($key) && !is_array($cache->get($key))) {
$cache->delete($key); // evict foreign/corrupt payload
}
$router->useCache($cache, $key); Defensive patterns
Strategy: validation
Validate before calling
// Evict a foreign payload before wiring the cache
if ($cache->has($key) && !is_array($cache->get($key))) {
$cache->delete($key);
}
$router->useCache($cache, $key); Type guard
function cacheSlotIsArray($cache, string $key): bool
{
return !$cache->has($key) || is_array($cache->get($key));
} Try / catch
try {
$router->useCache($cache, $key);
} catch (\Phalcon\Mvc\Router\Exception $e) {
$cache->delete($key); // drop the bad payload
$router->useCache($cache, $key); // miss path will repopulate it
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- Cannot cache router: route id '{routeId}' has a Closure befo
- Cannot cache router: route id '{routeId}' has a Closure conv
- Router cache is missing 'version' field
- Router cache version {dumpVersion} is not supported (this bu
- Router cache is missing 'routes' field
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/4033ec5af597931a.
Report an issue: GitHub.