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

Invalid route position

Error message

Invalid route position

What it means

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.

Source

Thrown at phalcon/Mvc/Router.zep:672

     *
     * @param RouteInterface $route
     * @param int            $position
     *
     * @return static
     */
    public function attach(
        <RouteInterface> route,
        int position = Router::POSITION_LAST
    ) -> <static> {
        switch position {
            case self::POSITION_LAST:
                let this->routes[] = route;
                break;
            case self::POSITION_FIRST:
                let this->routes = array_merge([route], this->routes);
                break;
            default:
                throw new InvalidRoutePosition();
        }

        let this->methodRoutesDirty = true;

        return this;
    }

    /**
     * Removes all the pre-defined routes
     */
    public function clear() -> void
    {
        let this->routes                 = [],
            this->methodRoutes           = [],
            this->candidatesByMethod     = [],
            this->routeMeta              = [],
            this->staticByMethod         = [],
            this->staticShadowedByMethod = [],

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Use only Router::POSITION_LAST or Router::POSITION_FIRST when calling attach()
  2. 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
  3. When positions come from config, whitelist-map them: 'first' => Router::POSITION_FIRST, 'last' => Router::POSITION_LAST, and reject anything else at load time

Example fix

// before
$router->attach($route, 2); // throws InvalidRoutePosition

// after
use Phalcon\Mvc\Router;
$router->attach($route, Router::POSITION_FIRST); // or Router::POSITION_LAST

// config-driven positions: map and validate
$map = ['first' => Router::POSITION_FIRST, 'last' => Router::POSITION_LAST];
$pos = $map[$definition['position'] ?? 'last'] ?? Router::POSITION_LAST;
$router->attach($route, $pos);
Defensive patterns

Strategy: validation

Validate before calling

use Phalcon\Mvc\Router;

$allowed = [Router::POSITION_FIRST, Router::POSITION_LAST];
if (!in_array($position, $allowed, true)) {
    throw new InvalidArgumentException('position must be Router::POSITION_FIRST or POSITION_LAST');
}
$router->attach($route, $position);

Type guard

function isValidAttachPosition(int $position): bool
{
    return in_array($position, [\Phalcon\Mvc\Router::POSITION_FIRST, \Phalcon\Mvc\Router::POSITION_LAST], true);
}

Try / catch

try {
    $router->attach($route, $position);
} catch (\Phalcon\Mvc\Router\Exceptions\InvalidRoutePosition $e) {
    $router->attach($route, \Phalcon\Mvc\Router::POSITION_LAST); // safe default
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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