
Gestionnaire d'erreurs global dans Vue 3 : ce que capte app.config.errorHandler, et ce qui lui échappe
- vuetelemetry
- Guides
- 8 min de lecture
app.config.errorHandler s'installe en trois lignes. Le vrai travail consiste à connaître les sept sources qu'il couvre, à comprendre pourquoi son troisième argument devient un code en production, comment onErrorCaptured peut le faire taire, et quelles erreurs seul le navigateur vous signalera.
Un composant lève une exception dans un watcher, sur le téléphone d'un client. En développement, la même panne aurait rempli l'écran d'une trace de pile. Dans un build de production, par défaut, Vue écrit l'erreur dans une console que personne ne regarde, et l'application continue dans l'état où la panne l'a laissée. Un gestionnaire d'erreurs global est la pièce qui transforme cette ligne silencieuse en quelque chose que l'on peut recevoir, compter et corriger.
Vue 3 en fournit un pour toute l'application : app.config.errorHandler. La référence officielle de l'API le décrit comme un gestionnaire global pour les erreurs non interceptées qui se propagent depuis l'intérieur de l'application. L'installer prend trois lignes. Le vrai travail consiste à savoir ce qu'il couvre, ce qu'il laisse de côté, et ce que contiennent ses arguments une fois le code compilé pour la production.
Ce que capte app.config.errorHandler

Le gestionnaire est une propriété de l'instance d'application : app.config.errorHandler = (err, instance, info) => { ... }. Il se place entre createApp() et app.mount(). Le guide de Vue est explicite sur l'ordre : toutes les configurations de l'application doivent être appliquées avant de la monter. La raison se voit bien ici, puisque le premier rendu et le setup() du composant racine s'exécutent tous deux au montage.
La référence énumère sept sources dont le gestionnaire peut capter les erreurs : les rendus de composants, les gestionnaires d'événements, les hooks de cycle de vie, la fonction setup(), les watchers, les hooks de directives personnalisées et les hooks de transition. Cette liste se lit comme un contrat. Elle décrit le code que Vue appelle pour vous. Le code qui s'exécute sans aucun appel de Vue au-dessus de lui dans la pile est une autre affaire, traitée plus bas dans sa propre section.
Trois arguments, et le piège de la production
Le gestionnaire reçoit trois arguments. Le premier est l'erreur, typée unknown dans la signature TypeScript, parce que JavaScript permet de lancer n'importe quoi : une chaîne, un objet simple, undefined. Vérifiez qu'il s'agit bien d'une instance d'Error avant de lire son message ou sa pile. Le deuxième est l'instance du composant qui a déclenché l'erreur, ou null. Le troisième, info, est une chaîne propre à Vue qui nomme le type de source, par exemple le hook de cycle de vie dans lequel l'erreur a été levée.
- app.config.errorHandler reçoit (err, instance, info) et se définit avant app.mount()
- Sept sources documentées : rendus de composants, gestionnaires d'événements, hooks de cycle de vie, setup(), watchers, hooks de directives personnalisées, hooks de transition
- Dans les builds de production, info est un code court ; la page Production Error Code Reference le ramène au texte
- Comportement par défaut : erreur relancée en développement, écrite dans la console en production ; throwUnhandledErrorInProduction (3.5+) change le second
- Un hook onErrorCaptured() qui renvoie false arrête l'erreur avant le gestionnaire global
- Hors de Vue : l'événement error de window pour les erreurs de script synchrones, unhandledrejection pour les promesses
Ce troisième argument réserve une surprise à qui ouvre un rapport de production pour la première fois. Dans les builds de production, info est un code abrégé et non la chaîne complète. La documentation de Vue tient une page Production Error Code Reference qui fait correspondre chaque code d'exécution à son texte d'origine. Envoyez la valeur brute telle qu'elle arrive et faites la correspondance au moment de lire le rapport. Une logique qui compare info à une chaîne vue en développement cessera de fonctionner une fois l'application compilée.
Développement et production ne se comportent pas pareil
Sans gestionnaire, ce que fait Vue dépend du build. Selon la référence, le gestionnaire par défaut relance les erreurs en développement et les journalise en production. La moitié développement est voulue. La documentation indique que l'erreur est lancée, et peut éventuellement faire planter l'application, afin d'être plus visible, donc remarquée et corrigée.
La moitié production a un effet de bord qui compte pour la surveillance. Une erreur seulement écrite dans la console n'est pas lancée, et la documentation note elle-même que cela peut empêcher les services de surveillance d'erreurs d'attraper celles qui ne surviennent qu'en production. Depuis Vue 3.5, un interrupteur existe pour ce cas : app.config.throwUnhandledErrorInProduction, un booléen qui vaut false par défaut. Réglé sur true, les erreurs non gérées sont lancées en mode production aussi.
onErrorCaptured : des barrières locales avant le gestionnaire global
Le gestionnaire global est le dernier arrêt. Avant lui, tout composant peut intercepter les erreurs venues de ses descendants avec onErrorCaptured(), ou errorCaptured dans l'Options API. Le hook reçoit les mêmes trois arguments et sert à bâtir une barrière d'erreur : modifier un état, afficher un contenu de repli. La référence y joint un avertissement. L'état d'erreur ne doit pas afficher le contenu d'origine qui a provoqué l'erreur, sinon le composant entre dans une boucle de rendu infinie.
La propagation suit quatre règles documentées. Par défaut, les erreurs captées sont quand même transmises à app.config.errorHandler s'il est défini, afin d'être signalées en un seul endroit. Si plusieurs hooks errorCaptured se trouvent sur la chaîne des parents, tous sont appelés, de bas en haut, à la manière du bouillonnement des événements DOM. Si un hook lève lui-même une erreur, celle-ci et l'erreur d'origine partent toutes deux vers le gestionnaire global. Enfin, un hook peut renvoyer false pour arrêter l'erreur sur place : aucun autre hook ni le gestionnaire global ne sera appelé pour elle. Cette dernière règle explique le plus souvent une erreur qui affiche un contenu de repli à l'écran sans jamais apparaître dans un rapport.
Ce que le gestionnaire global ne voit jamais
Vient la partie hors contrat. Une fonction passée à setTimeout, un écouteur posé à la main avec addEventListener, une chaîne de promesses lancée dans un module utilitaire, un script tiers : aucun ne fait partie des sept sources. Le navigateur a deux événements pour eux. D'après MDN, l'événement error se déclenche sur window lorsqu'une ressource n'a pas pu être chargée ou utilisée, par exemple quand un script rencontre une erreur d'exécution, et il n'est produit que pour les erreurs de script levées de façon synchrone. Une promesse rejetée sans gestionnaire de rejet, ce qui inclut un throw non intercepté dans une fonction async, déclenche à la place unhandledrejection.
Une installation complète compte donc trois écouteurs qui alimentent une seule fonction : app.config.errorHandler pour le code que Vue appelle, un écouteur error sur window pour les pannes synchrones survenues ailleurs, et un écouteur unhandledrejection pour les promesses que personne n'a interceptées. Oubliez-en un et toute une catégorie de pannes reste invisible.
Remonter l'erreur sans aggraver la situation
Ce que la fonction fait d'une erreur décide de l'utilité du gestionnaire. Gardez-la courte et défensive : normaliser l'erreur, y joindre info, la route courante et la version déployée, puis l'envoyer à votre point de collecte. Entourez son corps d'un try et d'un catch, car une fonction de signalement qui plante ajoute seulement une seconde panne à la première. Dédoublonnez avant l'envoi, puisqu'une erreur de rendu dans une liste peut se répéter à chaque ligne. Et conservez un appel à console.error dans le gestionnaire pendant le développement : une fois le vôtre installé, celui que Vue fournit par défaut, qui relance l'erreur en développement, ne s'exécute plus.
Les erreurs répondent à une seule question : qu'est-ce qui a cassé. Elles ne disent pas combien de temps l'utilisateur a attendu avant la panne, ni quelle requête était en cours à ce moment. C'est le domaine des traces, traité dans OpenTelemetry dans une app Vue. Commencez tout de même par le gestionnaire. Il tient en quelques lignes sans aucune dépendance, et il signale les problèmes que vous ne pensiez pas à chercher.
FAQ
Où définir le gestionnaire d'erreurs global dans Vue 3 ?
Sur l'instance d'application, entre createApp() et app.mount() : app.config.errorHandler = (err, instance, info) => { ... }. Le guide de Vue demande d'appliquer toutes les configurations de l'application avant de la monter.
app.config.errorHandler capte-t-il toutes les erreurs de la page ?
Non. La référence de Vue énumère sept sources : rendus de composants, gestionnaires d'événements, hooks de cycle de vie, setup(), watchers, hooks de directives personnalisées et hooks de transition. Les erreurs survenues en dehors sont signalées par le navigateur, via l'événement error de window pour les erreurs de script synchrones et via unhandledrejection pour les promesses rejetées sans gestionnaire.
Pourquoi l'argument info est-il un code et non une chaîne lisible en production ?
Dans les builds de production, Vue transmet un code abrégé comme troisième argument de app.config.errorHandler et de onErrorCaptured. La page Production Error Code Reference de la documentation de Vue fait correspondre chaque code d'exécution à sa chaîne d'information d'origine.
Quelle différence entre onErrorCaptured et app.config.errorHandler ?
onErrorCaptured est un hook de composant qui capte les erreurs des composants descendants, ce qui en fait l'outil d'un contenu de repli local. app.config.errorHandler vaut pour toute l'application et reçoit quand même ces erreurs par défaut, sauf si un hook renvoie false pour arrêter la propagation.



Une installation complète compte donc trois écouteurs qui alimentent une seule fonction : app.config.errorHandler pour le code que Vue appelle, un écouteur error sur window pour les pannes synchrones survenues ailleurs, et un écouteur unhandledrejection pour les promesses que personne n'a interceptées. Oubliez-en un et toute une catégorie de pannes reste invisible.