cakephp/cakephp · error · MissingRouteException
A named route was found for
Error message
A named route was found for `%s`, but matching failed. Passed parameters: `%s`.
What it means
RouteCollection::match() found a route registered with the given `_name`, but Route::match() could not produce a URL from the passed parameters — the parameters don't satisfy the route's template placeholders, defaults, or passed-argument pattern. Cake throws MissingRouteException because URL generation failed even though the route name exists.
Solutions
- Print the route template (Router::getRouteCollection()->get($name)->template and its defaults/patterns) and compare against the exact parameters passed in the failing Router::url()/match() call
- Supply every required placeholder in the URL array and remove keys the route template does not use (plugin/prefix/controller/action are ignored for named routes)
- Check route pattern constraints — e.g. an id pattern of \d+ fails for string identifiers; relax the pattern or pass a valid value
- If the route shape changed, update the _name reference or connect a new route with that name and the expected parameters
- Catch MissingRouteException around URL generation if the link is optional and can be skipped
Example fix
// before $url = Router::url(['_name' => 'articles:view', 'slug' => $article->slug]); // route: /articles/view/:id with [['id', '\d+')] // after $url = Router::url(['_name' => 'articles:view', 'id' => $article->id]);
Defensive patterns
Strategy: try-catch
Validate before calling
$collection = Router::getRouteCollection();
$route = $collection->get($name);
if ($route === null) {
throw new RuntimeException("Named route {$name} is not connected");
}
foreach ($route->options ?? [] as $key => $pattern) {
if (isset($url[$key]) && !preg_match('/^' . $pattern . '$/', (string)$url[$key])) {
throw new InvalidArgumentException("Parameter {$key} violates pattern {$pattern}");
}
} Type guard
function canGenerateUrl(string $name, array $url): bool {
$route = Router::getRouteCollection()->get($name);
return $route !== null && (bool)$route->match($url, []);
} Try / catch
try {
$url = Router::url(['_name' => 'articles:view', 'id' => $id]);
} catch (Cake\Routing\Exception\MissingRouteException $e) {
Log::error('Named route match failed: ' . $e->getMessage());
$url = '/';
} Prevention
- Keep named-route parameter keys in sync with route templates; prefer named routes with explicit placeholders
- Add integration tests that generate a URL for every named route in routes.php (like testPluginRoutes does)
- Review route pattern constraints (\d+ etc.) when identifiers can be non-numeric
- Grep for Router::url(['_name' => ...]) whenever a route template changes
When it happens
Trigger: Calling Router::url(['_name' => 'route:name', ...]) (which ends up in RouteCollection::match) with parameters that don't match the named route's template: missing a required placeholder value, wrong key names, extra/insufficient passed arguments, or a value that fails the route's regex/pattern constraints.
Common situations: Renaming or reshaping a route template in routes.php without updating every Router::url() call referencing it by _name; typos in parameter keys; passing plugin/prefix keys to a route defined without them; a pattern constraint (e.g. [['id', '\d+']]) rejecting a non-numeric id like a string slug; test code (e.g. testPluginRoutes) generating URLs with stale parameters.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Missing required route key
- URL filter defined in
- Cannot add middleware group
- Cannot add ' ' middleware to group ' '. It has not been…
- Cannot apply ` ` middleware or middleware group. Use…
AI-assisted analysis of cakephp/cakephp@1128eba9b0 (2026-09-12).
Data as JSON: /api/errors/b3939b39256ed041.
Report an issue: GitHub.
Appendix: source
Thrown at src/Routing/RouteCollection.php:298
public function match(array $url, array $context): string
{
// Named routes support optimization.
if (isset($url['_name'])) {
$name = $url['_name'];
unset($url['_name']);
if (isset($this->_named[$name])) {
$route = $this->_named[$name];
$out = $route->match($url + $route->defaults, $context);
if ($out) {
return $out;
}
$message = sprintf(
'A named route was found for `%s`, but matching failed. Passed parameters: `%s`.',
$name,
(string)json_encode($url),
);
throw new MissingRouteException([
'url' => $name,
'context' => $context,
// Escape `%` so the message survives CakeException's vsprintf() pass unchanged.
'message' => str_replace('%', '%%', $message),
]);
}
throw new MissingRouteException(['url' => $name, 'context' => $context]);
}
foreach ($this->_getNames($url) as $name) {
if (empty($this->_routeTable[$name])) {
continue;
}
foreach ($this->_routeTable[$name] as $route) {
$match = $route->match($url, $context);
if ($match) {
return $match === '/' ? $match : trim($match, '/');
}View on GitHub (pinned to 1128eba9b0)