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

'defaults' must be an array

Error message

'defaults' must be an array

What it means

Inside loadFromConfig(), the optional 'defaults' key sets router defaults via setDefaults(), which requires an array (e.g. ['module' => 'frontend', 'controller' => 'index']). If config['defaults'] exists but is a scalar, string, or object, the router throws ConfigKeyMustBeArray('defaults') naming the offending key.

Source

Thrown at phalcon/Mvc/Router.zep:1768

            if !(config instanceof ConfigInterface) {
                throw new InvalidConfigSource();
            }
            let config = config->toArray();
        }

        if typeof config !== "array" {
            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 {

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Make 'defaults' an array: "defaults": {"module": "frontend", "controller": "index", "action": "index"}
  2. If decoding JSON, pass true: json_decode($json, true) so nested objects become arrays
  3. Validate the shape before loading (see validation snippet) so the failure names the file, not the router

Example fix

// before
$config = json_decode(file_get_contents('routes.json'));
// {"defaults": "frontend"} -> stdClass/string defaults
$router->loadFromConfig($config);

// after
$config = json_decode(file_get_contents('routes.json'), true);
// {"defaults": {"module": "frontend", "controller": "index"}}
$router->loadFromConfig($config);
Defensive patterns

Strategy: validation

Validate before calling

// validate the whole router-config shape before handing it to the router
function validateRouterConfig(array $config): void
{
    if (isset($config['defaults']) && !is_array($config['defaults'])) {
        throw new InvalidArgumentException("'defaults' must be an array");
    }
    if (isset($config['routes']) && !is_array($config['routes'])) {
        throw new InvalidArgumentException("'routes' must be an array");
    }
    if (isset($config['groups']) && !is_array($config['groups'])) {
        throw new InvalidArgumentException("'groups' must be an array");
    }
}

validateRouterConfig($config);
$router->loadFromConfig($config);

Type guard

function defaultsAreValid(array $config): bool
{
    return !isset($config['defaults']) || is_array($config['defaults']);
}

Try / catch

try {
    $router->loadFromConfig($config);
} catch (\Phalcon\Mvc\Router\Exceptions\ConfigKeyMustBeArray $e) {
    // message names the offending key, e.g. "'defaults' must be an array"
    $logger->error('Router config key invalid: ' . $e->getMessage());
    throw $e;
}

Prevention

When it happens

Trigger: A config file containing "defaults": "frontend" or "defaults": {"module": "frontend"} decoded to an object (json_decode without true) instead of an array; a YAML defaults scalar.

Common situations: json_decode() without the $associative flag turning every nested object into stdClass; hand-edited YAML using a scalar where a map was intended; defaults written as a single string module name.

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/b4e415fd00f2fbcd. Report an issue: GitHub.