phalcon/cphalcon · error · Phalcon\Mvc\Router\Exceptions\ConfigKeyMustBeArray

'routes' must be an array

Error message

'routes' must be an array

What it means

In loadFromConfig(), the 'routes' key must be an array of route definition arrays (each with at least 'pattern' and 'paths'). If config['routes'] exists but is anything other than an array, ConfigKeyMustBeArray('routes') is thrown before any route is processed.

Source

Thrown at phalcon/Mvc/Router.zep:1775

            throw new InvalidConfigSource();
        }

        if isset config["removeExtraSlashes"] {
            let removeExtra = config["removeExtraSlashes"];
            this->removeExtraSlashes((bool) removeExtra);
        }

        if isset config["defaults"] {
            let defaults = config["defaults"];
            if typeof defaults !== "array" {
                throw new ConfigKeyMustBeArray("defaults");
            }
            this->setDefaults(defaults);
        }

        if fetch routes, config["routes"] {
            if typeof routes !== "array" {
                throw new ConfigKeyMustBeArray("routes");
            }
            for routeData in routes {
                this->addRouteFromConfig(routeData);
            }
        }

        if fetch groups, config["groups"] {
            if typeof groups !== "array" {
                throw new ConfigKeyMustBeArray("groups");
            }
            for groupData in groups {
                this->mountGroupFromConfig(groupData);
            }
        }

        if fetch notFoundPaths, config["notFound"] {
            this->notFound(notFoundPaths);
        }

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Wrap route entries in a list: "routes": [{"pattern": "/api", "paths": {...}}, ...]
  2. Decode JSON with json_decode($json, true) so objects inside 'routes' become arrays too
  3. Pre-validate the config shape (see validation snippet) and report the offending file/line

Example fix

// before
{
    "routes": {
        "pattern": "/api/users",
        "paths": {"controller": "users"}
    }
}

// after
{
    "routes": [
        {
            "pattern": "/api/users",
            "paths": {"controller": "users"}
        }
    ]
}
Defensive patterns

Strategy: validation

Validate before calling

// every entry under 'routes' must itself be an array containing pattern + paths
$routes = $config['routes'] ?? [];
if (!is_array($routes)) {
    throw new InvalidArgumentException("'routes' must be an array of route definitions");
}
foreach ($routes as $i => $entry) {
    if (!is_array($entry) || !isset($entry['pattern'], $entry['paths'])) {
        throw new InvalidArgumentException("routes[$i] must contain 'pattern' and 'paths'");
    }
}

$router->loadFromConfig($config);

Type guard

function routesAreValid(array $config): bool
{
    if (!isset($config['routes'])) {
        return true;
    }
    if (!is_array($config['routes'])) {
        return false;
    }
    foreach ($config['routes'] as $entry) {
        if (!is_array($entry) || !isset($entry['pattern'], $entry['paths'])) {
            return false;
        }
    }
    return true;
}

Try / catch

try {
    $router->loadFromConfig($config);
} catch (\Phalcon\Mvc\Router\Exceptions\ConfigKeyMustBeArray $e) {
    $logger->error('Router config rejected: ' . $e->getMessage());
    throw $e;
}

Prevention

When it happens

Trigger: "routes": {...} decoded as a JSON object; a single route definition passed directly under 'routes' instead of wrapped in a list; routes serialized as a string.

Common situations: json_decode without associative flag; writing a single route object under 'routes' ({"pattern": ..., "paths": ...}) instead of a one-element list ([{...}]); merging configs where a later override replaced the list with a scalar.

Understand the failure class

Background: Config validation failed: what "invalid value for {key}" and settings-rejection errors mean across 19 open-source libraries — this error's family across 19 libraries.

Related errors


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