{"record":{"id":"8fc43ad328eb0779","repo":"phalcon/cphalcon","slug":"invalid-route-position","errorCode":null,"errorMessage":"Invalid route position","messagePattern":"Invalid route position","errorType":"exception","errorClass":"Phalcon\\Mvc\\Router\\Exceptions\\InvalidRoutePosition","httpStatus":null,"severity":"error","filePath":"phalcon/Mvc/Router.zep","lineNumber":672,"sourceCode":"     *\n     * @param RouteInterface $route\n     * @param int            $position\n     *\n     * @return static\n     */\n    public function attach(\n        <RouteInterface> route,\n        int position = Router::POSITION_LAST\n    ) -> <static> {\n        switch position {\n            case self::POSITION_LAST:\n                let this->routes[] = route;\n                break;\n            case self::POSITION_FIRST:\n                let this->routes = array_merge([route], this->routes);\n                break;\n            default:\n                throw new InvalidRoutePosition();\n        }\n\n        let this->methodRoutesDirty = true;\n\n        return this;\n    }\n\n    /**\n     * Removes all the pre-defined routes\n     */\n    public function clear() -> void\n    {\n        let this->routes                 = [],\n            this->methodRoutes           = [],\n            this->candidatesByMethod     = [],\n            this->routeMeta              = [],\n            this->staticByMethod         = [],\n            this->staticShadowedByMethod = [],","sourceCodeStart":654,"sourceCodeEnd":690,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Mvc/Router.zep#L654-L690","documentation":"Router::attach() only accepts two positions: Router::POSITION_LAST (append) and Router::POSITION_FIRST (prepend). Any other integer hits the default branch and throws InvalidRoutePosition - attach() is not a general-purpose 'insert at index N' API.","triggerScenarios":"Calling $router->attach($route, 2) or any int other than the two constants; computing a position arithmetically (POSITION_FIRST + 1); passing a config-driven value like 'top'/'1' from a routes config file without mapping it to the constants.","commonSituations":"Assuming attach() supports arbitrary ordering indices because the signature takes an int; loading route definitions from config where position is a string that must be translated; copying code between router implementations with different position semantics.","solutions":["Use only Router::POSITION_LAST or Router::POSITION_FIRST when calling attach()","If routes must be ordered, attach them in the required order (FIRST for the ones that must win, LAST for the rest) instead of numeric positions","When positions come from config, whitelist-map them: 'first' => Router::POSITION_FIRST, 'last' => Router::POSITION_LAST, and reject anything else at load time"],"exampleFix":"// before\n$router->attach($route, 2); // throws InvalidRoutePosition\n\n// after\nuse Phalcon\\Mvc\\Router;\n$router->attach($route, Router::POSITION_FIRST); // or Router::POSITION_LAST\n\n// config-driven positions: map and validate\n$map = ['first' => Router::POSITION_FIRST, 'last' => Router::POSITION_LAST];\n$pos = $map[$definition['position'] ?? 'last'] ?? Router::POSITION_LAST;\n$router->attach($route, $pos);","handlingStrategy":"validation","validationCode":"use Phalcon\\Mvc\\Router;\n\n$allowed = [Router::POSITION_FIRST, Router::POSITION_LAST];\nif (!in_array($position, $allowed, true)) {\n    throw new InvalidArgumentException('position must be Router::POSITION_FIRST or POSITION_LAST');\n}\n$router->attach($route, $position);","typeGuard":"function isValidAttachPosition(int $position): bool\n{\n    return in_array($position, [\\Phalcon\\Mvc\\Router::POSITION_FIRST, \\Phalcon\\Mvc\\Router::POSITION_LAST], true);\n}","tryCatchPattern":"try {\n    $router->attach($route, $position);\n} catch (\\Phalcon\\Mvc\\Router\\Exceptions\\InvalidRoutePosition $e) {\n    $router->attach($route, \\Phalcon\\Mvc\\Router::POSITION_LAST); // safe default\n}","preventionTips":["Map config strings ('first'/'last') to the class constants at load time and reject unknown values","Never pass computed indices to attach(); order is expressed by FIRST vs LAST plus registration order","Add unit tests asserting attach() is only ever called with the two constants"],"tags":["phalcon","router","routing","invalid-argument"],"backgroundTag":"invalid-enum-argument","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}