{"record":{"id":"9c99cadca5785c93","repo":"phalcon/cphalcon","slug":"before-match-callback-is-not-callable-in-matched-r-9c99ca","errorCode":null,"errorMessage":"Before-Match callback is not callable in matched route","messagePattern":"Before-Match callback is not callable in matched route","errorType":"exception","errorClass":"Phalcon\\Mvc\\Router\\Exceptions\\BeforeMatchNotCallable","httpStatus":null,"severity":"error","filePath":"phalcon/Mvc/Router.zep","lineNumber":1353,"sourceCode":"\n                        let staticHostRegex = staticRoute->getCompiledHostName();\n\n                        if staticHostRegex !== null {\n                            let staticMatched = preg_match(staticHostRegex, currentHostName);\n                        } else {\n                            let staticMatched = currentHostName == staticHostname;\n                        }\n\n                        if !staticMatched {\n                            continue;\n                        }\n                    }\n\n                    let staticBeforeMatch = staticRoute->getBeforeMatch();\n\n                    if staticBeforeMatch !== null {\n                        if unlikely !is_callable(staticBeforeMatch) {\n                            throw new BeforeMatchNotCallable();\n                        }\n\n                        let routeFound = {staticBeforeMatch}(handledUri, staticRoute, this);\n\n                        if !routeFound {\n                            continue;\n                        }\n                    }\n\n                    let routeFound         = true,\n                        matches            = null,\n                        parts              = staticRoute->getPaths(),\n                        this->matchedRoute = staticRoute;\n\n                    break;\n                }\n            }\n        }","sourceCodeStart":1335,"sourceCodeEnd":1371,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Mvc/Router.zep#L1335-L1371","documentation":"During matching, when a static (literal-pattern) route has a beforeMatch callback attached, the router verifies it with is_callable() before invoking it. If the value is set but not callable - a string naming a nonexistent function/method, a malformed array callable, or a class that is not autoloadable at match time - BeforeMatchNotCallable is thrown while handling the request.","triggerScenarios":"->beforeMatch('App\\Filters\\Gate::check') where Gate::check does not exist (renamed/removed, typo, wrong namespace); array callable ['Filter', 'method'] where the method is not static or is misspelled; loading routes from a cache dump into a process whose autoloader cannot find the filter class (cache built in CLI, matched in web with a different autoload path).","commonSituations":"Renaming or deleting a filter class without regenerating route caches; typos in callable strings; non-public or instance methods referenced as static callables; composer autoload differences between the dumping environment and the serving environment.","solutions":["Fix the reference so it points at an existing, autoloadable static method: beforeMatch('App\\Filters\\AdminGate::check')","Verify with is_callable() at route-definition time (assert once during boot) so bad references fail at startup with your own context","Regenerate the router cache after renaming/moving any class referenced by beforeMatch callables","Ensure the autoloader covering the callable's class is active in every process that loads the cached routes (web + CLI)"],"exampleFix":"// before\n$router->add('/admin', ['controller' => 'admin', 'action' => 'index'])\n       ->beforeMatch('App\\Filter\\AdminGate::check'); // wrong namespace -> throws at match time\n\n// after: assert at definition time, reference a real method\nclass AdminGate { public static function check(string $uri, \\Phalcon\\Mvc\\Router\\RouteInterface $route): bool { /* ... */ return true; } }\n$cb = [AdminGate::class, 'check'];\nassert(is_callable($cb));\n$router->add('/admin', ['controller' => 'admin', 'action' => 'index'])\n       ->beforeMatch($cb);","handlingStrategy":"validation","validationCode":"// Assert every beforeMatch is really callable at definition time\nforeach ($router->getRoutes() as $route) {\n    $cb = $route->getBeforeMatch();\n    if ($cb !== null && !is_callable($cb)) {\n        throw new LogicException('Route ' . $route->getRouteId() . ' has a non-callable beforeMatch');\n    }\n}","typeGuard":"function isUsableBeforeMatch(mixed $cb): bool\n{\n    return $cb === null || is_callable($cb);\n}","tryCatchPattern":"try {\n    $router->handle();\n} catch (\\Phalcon\\Mvc\\Router\\Exceptions\\BeforeMatchNotCallable $e) {\n    // one route's guard references a missing class/method: fail loud, page 500 with context\n    $logger->critical('beforeMatch not callable: ' . $e->getMessage());\n    throw $e;\n}","preventionTips":["Reference beforeMatch guards as [ClassName::class, 'method'] so refactorings break at definition time","Regenerate router caches whenever classes named in route metadata change","Verify autoload coverage for filter classes in web, CLI, and worker processes"],"tags":["phalcon","router","before-match","invalid-callback"],"backgroundTag":"invalid-callback","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}