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

  1. Add a return statement so the controller returns a Response
  2. Wrap non-Response results: new JsonResponse($data) or $this->json($data)
  3. If returning null intentionally, ensure the kernel/view event converts it (or allow null return type semantics)
  4. 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

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


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)