{"record":{"id":"43c0bff4d23a91d0","repo":"phalcon/cphalcon","slug":"group-routes-must-be-an-array","errorCode":null,"errorMessage":"Group 'routes' must be an array","messagePattern":"Group 'routes' must be an array","errorType":"exception","errorClass":"Phalcon\\Mvc\\Router\\Exceptions\\GroupRoutesMustBeArray","httpStatus":null,"severity":"error","filePath":"phalcon/Mvc/Router.zep","lineNumber":2141,"sourceCode":"            let paths = groupData[\"paths\"];\n        }\n\n        let group = new Group(paths);\n\n        if isset groupData[\"prefix\"] {\n            group->setPrefix((string) groupData[\"prefix\"]);\n        }\n\n        if isset groupData[\"hostname\"] {\n            group->setHostname((string) groupData[\"hostname\"]);\n        }\n\n        if !fetch routes, groupData[\"routes\"] {\n            let routes = [];\n        }\n\n        if typeof routes !== \"array\" {\n            throw new GroupRoutesMustBeArray();\n        }\n\n        for routeData in routes {\n            if !fetch pattern, routeData[\"pattern\"] {\n                throw new MissingGroupRouteKey(\"pattern\");\n            }\n            if !fetch routePaths, routeData[\"paths\"] {\n                throw new MissingGroupRouteKey(\"paths\");\n            }\n\n            let method = \"\";\n            if isset routeData[\"method\"] && routeData[\"method\"] !== null {\n                let method = strtolower((string) routeData[\"method\"]);\n            }\n\n            switch method {\n                case \"\":\n                case \"connect\":","sourceCodeStart":2123,"sourceCodeEnd":2159,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Mvc/Router.zep#L2123-L2159","documentation":"For each entry under config['groups'] (processed by mountGroupFromConfig), the optional inner 'routes' key must be an array of route definitions. A missing key defaults to an empty list, but if the key is present with a non-array value (object, string, scalar), GroupRoutesMustBeArray is thrown.","triggerScenarios":"JSON group object where \"routes\": {...} decodes to stdClass (json_decode without true); a group with \"routes\": \"see other file\"; single route object instead of a list under a group.","commonSituations":"Non-associative json_decode of the whole config (outer arrays survive only if wrapped in []); manual YAML authoring nesting an object where a list is required; config merging that replaced the list.","solutions":["Make group 'routes' a list: \"groups\": [{\"prefix\": \"/admin\", \"routes\": [{\"pattern\": ..., \"paths\": ...}]}]","Decode config with json_decode($json, true) so nested objects become arrays","Pre-validate group entries before loadFromConfig"],"exampleFix":"// before\n{\n    \"groups\": [\n        {\n            \"prefix\": \"/admin\",\n            \"routes\": {\n                \"pattern\": \"/dashboard\",\n                \"paths\": {\"controller\": \"dashboard\"}\n            }\n        }\n    ]\n}\n\n// after\n{\n    \"groups\": [\n        {\n            \"prefix\": \"/admin\",\n            \"routes\": [\n                {\n                    \"pattern\": \"/dashboard\",\n                    \"paths\": {\"controller\": \"dashboard\"}\n                }\n            ]\n        }\n    ]\n}","handlingStrategy":"validation","validationCode":"// validate group structure: each group is a map; its 'routes' (if present) is a list\nforeach ($config['groups'] ?? [] as $i => $group) {\n    if (!is_array($group)) {\n        throw new InvalidArgumentException(\"groups[$i] must be an array\");\n    }\n    if (isset($group['routes']) && !is_array($group['routes'])) {\n        throw new InvalidArgumentException(\"groups[$i]['routes'] must be an array\");\n    }\n}\n\n$router->loadFromConfig($config);","typeGuard":"function groupRoutesAreValid(mixed $group): bool\n{\n    return is_array($group)\n        && (!isset($group['routes']) || is_array($group['routes']));\n}","tryCatchPattern":"try {\n    $router->loadFromConfig($config);\n} catch (\\Phalcon\\Mvc\\Router\\Exceptions\\GroupRoutesMustBeArray $e) {\n    $logger->error('Group config rejected: ' . $e->getMessage());\n    throw $e;\n}","preventionTips":["A group's 'routes' is a list of entries — never a single object or string","Omit 'routes' entirely for prefix-only shells (it defaults to empty)","Always decode route JSON/YAML to associative arrays"],"tags":["phalcon","router","config","groups","validation"],"backgroundTag":"invalid-route-configuration","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}