phalcon/cphalcon · error · Phalcon\Mvc\Router\Exceptions\ConfigKeyMustBeArray
'groups' must be an array
Error message
'groups' must be an array
What it means
In loadFromConfig(), the optional 'groups' key must be an array of group definition arrays (each may carry 'prefix', 'hostname', 'routes', and per-route entries). If config['groups'] exists but is not an array, ConfigKeyMustBeArray('groups') is thrown before any group is mounted.
Source
Thrown at phalcon/Mvc/Router.zep:1784
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);
}
return this;
}
/**
* Mounts a group of routes in the router
*
* @param GroupInterface group
*View on GitHub (pinned to b7419de9cd)
Solutions
- Wrap each group in a list: "groups": [{"prefix": "/admin", "routes": [...]}, ...]
- Use json_decode($json, true) so nested group objects arrive as arrays
- Pre-validate the 'groups' key is a list before calling loadFromConfig
Example fix
// before
{
"groups": {
"prefix": "/admin",
"routes": [{"pattern": "/dashboard", "paths": {...}}]
}
}
// after
{
"groups": [
{
"prefix": "/admin",
"routes": [{"pattern": "/dashboard", "paths": {...}}]
}
]
} Defensive patterns
Strategy: validation
Validate before calling
// 'groups' must be a list of group definitions, each with an array 'routes' (optional)
$groups = $config['groups'] ?? [];
if (!is_array($groups)) {
throw new InvalidArgumentException("'groups' must be an array of group definitions");
}
foreach ($groups as $i => $group) {
if (!is_array($group) || (isset($group['routes']) && !is_array($group['routes']))) {
throw new InvalidArgumentException("groups[$i] invalid: 'routes' must be an array");
}
}
$router->loadFromConfig($config); Type guard
function groupsAreValid(array $config): bool
{
if (!isset($config['groups'])) {
return true;
}
if (!is_array($config['groups'])) {
return false;
}
foreach ($config['groups'] as $group) {
if (!is_array($group) || (isset($group['routes']) && !is_array($group['routes']))) {
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
- Model groups as a list of maps; each group's 'routes' is itself a list
- Decode with associative=true everywhere route config is parsed
- Lint YAML/JSON route files in CI to catch object-vs-list mixups
When it happens
Trigger: "groups": {"prefix": "/admin", "routes": [...} (a single group object instead of a list of groups); groups decoded to stdClass by json_decode without true; groups defined as a comma-separated string.
Common situations: Same JSON object-vs-array decode issue as 'routes'; defining one group inline without the enclosing [ ]; config merges that overwrite the groups list with a non-array.
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
- Group 'routes' must be an array
- Group route entry is missing 'pattern'
- Group route entry is missing 'paths'
- loadFromConfig requires an array or Phalcon\Config\ConfigInt
- 'defaults' must be an array
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/7295a67a4189889c.
Report an issue: GitHub.