feat: make server errors visible to the user for htmx requests

This commit is contained in:
Björn Fromme
2026-07-02 10:02:05 +02:00
parent 4d3fc69faa
commit de37186706
2 changed files with 65 additions and 0 deletions
@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
namespace App\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Twig\Environment;
/**
* Returns an error modal for unhandled exceptions on HTMX requests.
*
* Without this, a 500 from an HTMX endpoint is silently discarded by the browser
* and the user sees nothing. This listener intercepts those exceptions and returns
* a 200 with the error modal HTML, using HX-Retarget/HX-Reswap to append it to
* <body> regardless of the original hx-target.
*/
class HtmxExceptionListener implements EventSubscriberInterface
{
public function __construct(private readonly Environment $twig)
{
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::EXCEPTION => ['onKernelException', -10],
];
}
public function onKernelException(ExceptionEvent $event): void
{
if (false === $event->getRequest()->headers->has('HX-Request')) {
return;
}
if ($event->hasResponse()) {
return;
}
$html = $this->twig->render('htmx_error_modal.html.twig');
$response = new Response($html, Response::HTTP_OK);
$response->headers->set('HX-Retarget', 'body');
$response->headers->set('HX-Reswap', 'beforeend');
$event->setResponse($response);
$event->allowCustomResponseCode();
}
}
+12
View File
@@ -0,0 +1,12 @@
{% embed '_partials/_modal.html.twig' with { 'level': 'error' } %}
{% block title %}
Oops...
{% endblock %}
{% block content %}
{% include '_partials/_alert.html.twig' with {
level: 'error',
modal: true,
messages: ['Da ist etwas schiefgelaufen. Wir haben uns Notizen gemacht und kümmern uns schnellstmöglich darum.']
} %}
{% endblock %}
{% endembed %}