Débugger une application Symfony ne devrait pas être une course d'obstacles. Pourtant, deux irritants traînent depuis des années dans le quotidien des équipes qui travaillent avec le framework : une page d'exception qui devient illisible dès que la stack trace s'allonge, et un AssetMapper qui refuse obstinément de refléter les changements de code tant qu'on n'a pas vidé à la main le cache d'assets compilés. Ces deux frictions touchent directement l'expérience développeur au moment précis où elle compte le plus — celui où quelque chose casse et où il faut comprendre pourquoi, vite. Deux chantiers en cours sur la branche 8.2 de Symfony s'attaquent frontalement à ce problème : la refonte de la page d'exception portée par la PR #64766 sur le composant ErrorHandler, et le fix #64852 qui rend AssetMapper enfin cohérent entre mode debug et mode production. Aucun des deux n'est encore disponible en version stable — 8.1 reste la dernière release publiée — mais les deux méritent d'être suivis de près tant ils changent le quotidien de debug.
Le rôle de l'ErrorHandler dans le cycle de debug
Le composant ErrorHandler est le point de passage obligé de toute exception non rattrapée dans une application Symfony. Il intercepte les Throwable, les normalise en FlattenException — une représentation sérialisable de l'exception, indépendante du contexte HTTP ou CLI — puis choisit le rendu selon l'environnement. En APP_ENV=dev avec APP_DEBUG=1, il affiche la page d'exception détaillée que tout développeur Symfony connaît par cœur : message, stack trace, requête, et onglets additionnels quand le profiler est actif. En production, le même flux redirige vers les pages d'erreur personnalisées définies par ton ExceptionListener, sans jamais exposer de détail interne. C'est cette page de développement — celle qu'on regarde vingt fois par jour en phase d'implémentation — qui fait l'objet de la refonte en discussion.
PR #64766 : une refonte complète de la page d'exception
La page d'exception actuelle affiche la chaîne de causes (getPrevious()) sous forme de fil d'Ariane cliquable, avec un empilement de trois onglets — Exception, Logs, Stack Trace — sur une même page. Le résultat est fonctionnel mais dense : dès qu'une exception encapsule deux ou trois causes successives (typiquement une PDOException remontée en ORMException puis en exception métier), l'information utile se dilue dans l'accumulation d'onglets et de sections. La PR #64766, ouverte sur le dépôt symfony/symfony et ciblant la branche 8.2, propose une réécriture du template de rendu avec plusieurs changements structurants.
- Timeline interactive à la place du fil d'Ariane — chaque exception de la chaîne devient un point sélectionnable indépendamment, et seul le détail de l'exception choisie s'affiche, ce qui réduit la charge cognitive sur les chaînes longues
- Page unique à sections repliables au lieu des trois onglets Exception / Logs / Stack Trace — les frames vendor sont masquées par défaut, les logs non-erreur sont repliés à l'ouverture
- Bouton « Copy as text » qui formate stack trace et logs dans un texte brut directement exploitable, pensé pour être collé dans un assistant IA en cours de triage
- Recherche plein texte dans les logs, avec filtrage à la volée
- Bascule stack trace formatée / brute et coloration syntaxique harmonisée sur toutes les sections de code
- Mode « true dark » et mise en page responsive, avec un rendu cohérent entre la page autonome et son intégration dans le profiler
Au moment d'écrire ces lignes, la PR est marquée comme revue et approuvée par un mainteneur, avec des itérations mineures encore en cours sur l'ordre de la timeline et l'intensité de certains contrastes visuels. Elle n'est pas mergée dans la branche 8.2 : ces détails de rendu peuvent donc encore évoluer avant la release stable, attendue en novembre 2026. Pour les équipes qui suivent déjà l'évolution du framework — notamment la bascule vers les applications HTTP-less détaillée dans notre article sur Symfony 8.1, DeepCloner et les commandes multi-méthodes —, cette refonte confirme une tendance de fond : le framework investit autant dans l'outillage de debug que dans les fonctionnalités runtime.
AssetMapper en debug : le cache compilé qui ment sur tes changements
AssetMapper fonctionne selon un principe simple : un fichier importmap.php déclare les correspondances entre modules JS/CSS et fichiers physiques dans assets/, et la commande bin/console asset-map:compile génère un manifeste versionné dans public/assets/ pour la production. En développement, le comportement attendu est que chaque requête recalcule le contenu des fichiers à la volée, sans étape de compilation — c'est tout l'intérêt du zero build. Le problème, documenté depuis plusieurs mois dans les issues #54520 et #53669 du dépôt symfony/symfony, est que dès qu'un manifeste compilé existe dans public/assets/ — parce qu'on a lancé la commande une fois pour tester un build de prod, ou parce qu'un script CI l'a généré localement — AssetMapper continue de le lire même en mode debug. Résultat : les modifications de code source deviennent invisibles tant qu'on n'a pas supprimé le manifeste à la main.
# Symptôme typique avant le fix #64852
bin/console asset-map:compile # génère public/assets/manifest.json
# ... on modifie assets/styles/app.css ...
# le changement n'apparaît pas tant que le manifeste n'est pas purgé manuellement
rm -rf public/assets/ && bin/console cache:clearLe fix #64852 : ignorer le manifeste compilé dès que debug est actif
Le correctif #64852, mergé sur la branche 8.2 le 10 juillet 2026, cible directement la classe CompiledAssetMapperConfigReader — le composant responsable de lire le manifeste compilé et de décider s'il faut l'utiliser. Le changement est chirurgical : un paramètre $debug est injecté dans le constructeur via le paramètre kernel.debug du conteneur, et la méthode configExists() retourne désormais systématiquement false lorsque le debug est actif, forçant AssetMapper à résoudre chaque asset dynamiquement depuis les sources. En production, où kernel.debug vaut false, le comportement historique est intégralement préservé : le manifeste compilé reste la source de vérité, exactement comme avant.
Migration Symfony en vue ?
Bear Upgrade migre votre codebase 2,5× à 4,5× moins cher qu'une ESN, selon sa maturité.
<?php
// Simplification illustrative du changement apporté par la PR #64852
final class CompiledAssetMapperConfigReader
{
public function __construct(
private readonly string $manifestPath,
private readonly bool $debug,
) {
}
public function configExists(): bool
{
if ($this->debug) {
// En debug, on ignore volontairement le manifeste compilé
// pour forcer la résolution dynamique depuis les sources.
return false;
}
return is_file($this->manifestPath);
}
}La nuance importante ici est que ce n'est pas un simple contournement au niveau CLI comme le proposait une tentative précédente (asset-map:compile nettoyant les assets en debug, avec un flag --force pour forcer la génération) — cette approche avait été fermée après discussion, les mainteneurs jugeant qu'elle créait une incohérence entre debug et non-debug sans traiter la cause racine. Le fix retenu agit plus bas, directement sur la lecture de configuration, ce qui évite toute dépendance à l'ordre d'exécution des commandes. Si tu viens d'un projet migré depuis Webpack Encore — un sujet qu'on a couvert en détail dans notre article sur la migration AssetMapper de Symfony 7.1 sans Node —, ce correctif referme définitivement l'un des derniers pièges hérités de la transition : le manifeste de build qui traînait en local et polluait silencieusement l'environnement de dev.
Un workflow debug propre, dev vs prod
Ce fix ne dispense pas de structurer correctement le pipeline de build. La bonne pratique reste de ne jamais committer public/assets/ et de réserver asset-map:compile à l'étape build d'un Dockerfile multi-stage, jamais à un conteneur de développement. Voici la configuration qui correspond à ce partage net entre les deux mondes.
# config/packages/asset_mapper.yaml
framework:
asset_mapper:
paths:
- assets/
# exclut les sources non pertinentes du scan (tests, fixtures...)
exclude_patterns:
- '/assets/**/*.test.js'
- '/assets/vendor/**/*'
when@prod:
framework:
asset_mapper:
# en prod, le manifeste compilé reste la seule source de vérité
# (comportement inchangé, aucune option supplémentaire requise)Concrètement, un conteneur de dev n'a désormais plus aucune raison de lancer asset-map:compile — même par erreur ou par habitude héritée d'un ancien script —, puisque la présence d'un manifeste ne change plus rien tant que kernel.debug est actif. Le seul endroit où la commande doit apparaître est l'étape build de ton image de production, en environnement APP_ENV=prod.
Le combo qui change vraiment le quotidien de debug
Pris isolément, chacun de ces deux chantiers est une amélioration ciblée. Mis bout à bout, ils redessinent un scénario de debug très courant : un développeur ajuste une feuille de style pendant qu'il traque un bug d'affichage, tombe sur une exception PHP en cours de route, et doit inspecter une stack trace pour comprendre l'origine du problème. Avec le fix AssetMapper, son changement CSS s'affiche immédiatement, sans qu'il ait besoin de se souvenir de purger un cache. Avec la nouvelle page d'exception, il peut isoler la cause racine dans la timeline plutôt que de dérouler un fil d'Ariane, puis copier la stack trace formatée d'un clic pour la coller dans sa session Claude Code et demander un diagnostic assisté. Ce même effort de lisibilité au moment du debug se retrouve dans les évolutions frontend plus larges du framework, que nous avons documentées dans notre tour d'horizon de Symfony UX 3.3 et ses nouveautés : l'écosystème converge vers une expérience de développement plus directe, moins ponctuée d'étapes manuelles.
- Ne fige pas encore le rendu exact de la page d'exception dans une documentation interne — la PR #64766 est encore susceptible d'évoluer avant merge
- Audite tes conteneurs de dev : si un script lance encore
asset-map:compilelocalement, retire-le une fois sur Symfony 8.2, il n'apporte plus rien en debug - Garde
public/assets/hors de Git — le fix #64852 réduit le risque, mais un manifeste committé reste une source de confusion en équipe - Suis la branche 8.2 sur GitHub si tu es en phase de montée de version active : ces deux changements ne sont pas rétroportés sur 8.1
Ces deux chantiers illustrent un point que beaucoup d'équipes sous-estiment : la vélocité d'une équipe Symfony ne se joue pas uniquement sur l'architecture ou les performances, elle se joue aussi sur la friction quotidienne — celle qu'on ne mesure jamais mais qu'on ressent à chaque session de debug. Si ta stack accumule encore des scripts de contournement pour AssetMapper, une CI qui ne détecte pas les régressions de build, ou un cycle de montée de version qui traîne, c'est souvent le signe qu'un audit technique ciblé vaut mieux qu'une nouvelle rustine. C'est exactement le type de sujet qu'on traite en accompagnement Symfony chez The Bearded Bear, du diagnostic jusqu'à la mise en œuvre.

Écrit par
Flavien Métivier
Expert PHP/Symfony indépendant depuis 2014, ancien CTO de Kartable et d'Extrabat. Plus de 80 projets menés, de l'audit à la migration.
Mon parcours