symfony/http-kernel · error · InvalidArgumentException
The controller for URI
Error message
The controller for URI "%s" is not callable:
What it means
ControllerResolver::getController resolved the _controller attribute from the Request, but the resulting value is not callable. The message is appended with getControllerError() explaining why (e.g. class does not exist, method missing).
Solutions
- Fix the _controller value in the route definition to an existing, public, callable controller
- Check the appended detail from getControllerError() to see whether the class or the method is missing
- Clear the cache (cache:clear) so compiled route/controller data matches current code
- If using a service controller, ensure the service exists and use 'serviceId::method' or 'serviceId:methodName' syntax
Example fix
// before
#[Route('/foo', name: 'foo', '_controller' => 'App\\Controller\\FooControler::index')]
// after
#[Route('/foo', name: 'foo', '_controller' => 'App\\Controller\\FooController::index')]
Defensive patterns
Strategy: validation
Validate before calling
$ctrl = $request->attributes->get('_controller');
if (is_string($ctrl) && !is_callable($ctrl, true)) {
[$class, $method] = array_pad(explode('::', $ctrl, 2), 2, '__invoke');
if (!class_exists($class) || !method_exists($class, $method)) {
throw new \InvalidArgumentException("Controller '$ctrl' is not callable");
}
} Type guard
function isStringCallableController(mixed $c): bool { return is_string($c) && is_callable($c, true); } Try / catch
try { $controller = $resolver->getController($request); } catch (\InvalidArgumentException $e) {
// 'The controller for URI ... is not callable'
} Prevention
- Use #[Route('/x', name: 'x')] attributes without manual _controller strings where possible
- Use bin/console debug:router and lint:container to validate routes and controllers
- Keep action methods public
- Clear cache after renaming controllers or methods
When it happens
Trigger: Request attributes contain a _controller value that resolves to a string or array that is_callable() rejects: a non-existent class::method, an instantiated object with an undefined method, or a malformed 'Class::method' string when the controller was found via the fallback path (not createController).
Common situations: Typo in _controller name in route annotations/attributes or YAML; controller method renamed or made private; controller string like 'App\\Controller\\Foo::bar' where class exists but ::bar does not; using a service method string without container support.
Related errors
- Controller " " does neither exist as service nor as class.
- Controller " " cannot be fetched from the container because…
- Message built by getControllerError(): e.g. Function
- You can only pin one resolver per argument, but argument "$
- " ::resolve()" must yield at most one value for…
AI-assisted analysis of symfony/http-kernel@aa3a39d728 (2026-09-13).
Data as JSON: /api/errors/bf26e5bbf778b9b9.
Report an issue: GitHub.
Appendix: source
Thrown at Controller/ControllerResolver.php:76
return false;
}
if (\is_array($controller)) {
if (isset($controller[0]) && \is_string($controller[0]) && isset($controller[1])) {
try {
$controller[0] = $this->instantiateController($controller[0]);
} catch (\Error|\LogicException $e) {
if (\is_callable($controller)) {
return $this->checkController($request, $controller);
}
throw $e;
}
}
if (!\is_callable($controller)) {
throw new \InvalidArgumentException(\sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$this->getControllerError($controller));
}
return $this->checkController($request, $controller);
}
if (\is_object($controller)) {
if (!\is_callable($controller)) {
throw new \InvalidArgumentException(\sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$this->getControllerError($controller));
}
return $this->checkController($request, $controller);
}
if (\function_exists($controller)) {
return $this->checkController($request, $controller);
}
try {View on GitHub (pinned to aa3a39d728)