symfony/http-kernel · error · ControllerDoesNotReturnResponseException
The controller must return a…
Error message
The controller must return a "Symfony\Component\HttpFoundation\Response" object but it returned %s. Did you forget to add a return statement somewhere in your controller?
What it means
The kernel requires every controller to return a Symfony Response object (or null when allowNull is set, which then also triggers this exception if a response is mandatory). If the controller returns any other type, ControllerDoesNotReturnResponseException is thrown with this message, hinting at a forgotten return statement.
Solutions
- Add a return statement so the controller returns a Response
- Wrap non-Response results: new JsonResponse($data) or $this->json($data)
- If returning null intentionally, ensure the kernel/view event converts it (or allow null return type semantics)
- Add a controller return type declaration (Response) so static analysis catches it
Example fix
// before
public function index(): JsonResponse
{
$this->json(['ok' => true]);
}
// after
public function index(): JsonResponse
{
return $this->json(['ok' => true]);
} Defensive patterns
Strategy: type-guard
Validate before calling
// static analysis: enforce return types // /** @return Response */ and run PHPStan/Psalm level that flags missing returns
Type guard
function assertResponse(mixed $result): \Symfony\Component\HttpFoundation\Response {
if (!$result instanceof \Symfony\Component\HttpFoundation\Response) {
throw new \TypeError('Controller must return a Response, got '.get_debug_type($result));
}
return $result;
} Try / catch
try { $response = $kernel->handle($request); } catch (ControllerDoesNotReturnResponseException $e) { /* points at offending controller file:line */ } Prevention
- Declare Response (or JsonResponse) return types on all controllers
- Never rely on returning plain arrays without a view/serializer listener
- Run PHPStan/Psalm with missing-return checks in CI
- Grep for controllers without `return` before building the response
When it happens
Trigger: A controller returns null, a string, an array, or a non-Response object while the kernel still requires a Response (no view event produced one and null is not allowed).
Common situations: Forgot `return` before `$this->json(...)`; controller returns an array without the serializer view listener handling it; returning void by accident; refactoring that changed the return type.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Request payload contains invalid "form" data.
- Unsupported format: " ".
- Request payload contains invalid
- Request payload contains invalid
- The uid for the " " parameter is invalid.
AI-assisted analysis of symfony/http-kernel@aa3a39d728 (2026-09-13).
Data as JSON: /api/errors/9930ed490eb6af87.
Report an issue: GitHub.
Appendix: source
Thrown at HttpKernel.php:205
// call controller
$response = $controller(...$arguments);
// view
if (!$response instanceof Response) {
$event = new ViewEvent($this, $request, $type, $response, $controllerMetadata);
$this->dispatcher->dispatch($event, KernelEvents::VIEW);
if ($event->hasResponse()) {
$response = $event->getResponse();
} else {
$msg = \sprintf('The controller must return a "Symfony\Component\HttpFoundation\Response" object but it returned %s.', $this->varToString($response));
// the user may have forgotten to return something
if (null === $response) {
$msg .= ' Did you forget to add a return statement somewhere in your controller?';
}
throw new ControllerDoesNotReturnResponseException($msg, $controller, __FILE__, __LINE__ - 17);
}
}
return $this->filterResponse($response, $request, $type, $controllerMetadata);
}
/**
* Filters a response object.
*
* @throws \RuntimeException if the passed object is not a Response instance
*/
private function filterResponse(Response $response, Request $request, int $type, ?ControllerMetadata $controllerMetadata = null): Response
{
$event = new ResponseEvent($this, $request, $type, $response, $controllerMetadata instanceof ControllerArgumentsMetadata ? $controllerMetadata : null);
$this->dispatcher->dispatch($event, KernelEvents::RESPONSE);
$this->finishRequest($request, $type, $controllerMetadata);View on GitHub (pinned to aa3a39d728)