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

  1. Clear the offending key before enabling router caching: $cache->delete($key) (or flush the namespace), then let useCache()'s miss path populate it
  2. Use a dedicated, namespaced key unique to this app and format: 'app:router:dispatcher:v1'
  3. Verify adapter serializer settings round-trip arrays (set and get an array in a smoke test)
  4. 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

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


AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21). Data as JSON: /api/errors/4033ec5af597931a. Report an issue: GitHub.