phalcon/cphalcon · error · Phalcon\Cli\Router\Exceptions\BeforeMatchNotCallable

Before-Match callback is not callable in matched route '{pat

Error message

Before-Match callback is not callable in matched route '{pattern}'

What it means

Route::beforeMatch() validates its argument immediately when the callback is set on a CLI route. It accepts only what is_callable() accepts: a closure, an invokable object, an existing function-name string, or a [object, 'method'] array. Anything else — a bare method-name string, a boolean flag, a config key — throws BeforeMatchNotCallable with the route pattern.

Source

Thrown at phalcon/Cli/Router/Route.zep:124

     * route id, so resetting the sequence while a router still holds routes
     * makes newly created routes overwrite existing entries.
     */
    public static function reset() -> void
    {
        let self::uniqueId = 0;
    }

    /**
     * Sets a callback that is called if the route is matched.
     * The developer can implement any arbitrary conditions here
     * If the callback returns false the route is treated as not matched
     *
     * @param mixed callback
     */
    public function beforeMatch(var callback) -> <RouteInterface>
    {
        if unlikely !is_callable(callback) {
            throw new BeforeMatchNotCallable(this->pattern);
        }

        let this->beforeMatch = callback;

        return this;
    }

    /**
     * Replaces placeholders from pattern returning a valid PCRE regular
     * expression
     */
    public function compilePattern( string pattern) -> string
    {
        var idPattern;
        array map;

        // If a pattern contains ':', maybe there are placeholders to replace
        if memstr(pattern, ":") {

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Pass a closure: $route->beforeMatch(function ($args, $route, $router) { return true; })
  2. For methods use the array form [$this, 'check'] or a static callable ['Checker', 'allowed']
  3. For named functions, pass only the name of a function that actually exists

Example fix

// before
$route->beforeMatch('checkMaintenance');

// after
$route->beforeMatch(function ($args, $route, $router) {
    return !file_exists('/tmp/maintenance.lock');
});
Defensive patterns

Strategy: validation

Validate before calling

$callback = function ($args, $route, $router) {
    return php_sapi_name() === 'cli';
};
assert(is_callable($callback)); // trivially true, but guards refactors to arrays/strings
$route->beforeMatch($callback);

Type guard

/**
 * beforeMatch accepts closures, invokable objects, existing function
 * names, and [object, method] arrays — exactly what is_callable allows.
 */
function isBeforeMatchCallback($value): bool
{
    return is_callable($value);
}

Try / catch

try {
    $route->beforeMatch($callback);
} catch (\Phalcon\Cli\Router\Route\Exception\BeforeMatchNotCallable $e) {
    // Message contains the route pattern; fix the callback reference at the call site
    throw new LogicException('Invalid beforeMatch for ' . $e->getMessage(), 0, $e);
}

Prevention

When it happens

Trigger: $route->beforeMatch('isAdmin') where no global function isAdmin exists; $route->beforeMatch([$this, 'check']) where the class defines no check() method; $route->beforeMatch('true') used as an on/off switch.

Common situations: Passing a method name string instead of the [$object, 'method'] array; typos in function/method names; treating beforeMatch like a boolean option after reading simplified examples.

Related errors


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