
Globaler Error Handler in Vue 3: Was app.config.errorHandler abfängt und was ihm entgeht
- vuetelemetry
- Leitfäden
- 8 Min. Lesezeit
app.config.errorHandler ist in drei Zeilen eingerichtet. Die eigentliche Arbeit: die sieben Quellen kennen, die er abdeckt, verstehen, warum sein drittes Argument im Produktionsbuild zu einem Code wird, wie onErrorCaptured ihn stummschalten kann und welche Fehler nur der Browser meldet.
Eine Komponente wirft in einem Watcher einen Fehler, auf dem Handy eines Kunden. In der Entwicklung hätte derselbe Fehler den Bildschirm mit einem Stacktrace gefüllt. Im Produktionsbuild schreibt Vue ihn standardmäßig in eine Konsole, in die niemand schaut, und die App läuft in dem Zustand weiter, den der Fehler hinterlassen hat. Ein globaler Error Handler ist das Bauteil, das aus dieser stillen Zeile etwas macht, das sich empfangen, zählen und beheben lässt.
Vue 3 bringt einen für die ganze Anwendung mit: app.config.errorHandler. Die offizielle API-Referenz beschreibt ihn als globalen Handler für nicht abgefangene Fehler, die sich aus der Anwendung heraus fortpflanzen. Das Einrichten kostet drei Zeilen. Die eigentliche Arbeit besteht darin zu wissen, was er abdeckt, was er auslässt und was seine Argumente enthalten, sobald der Code für die Produktion gebaut ist.
Was app.config.errorHandler abfängt

Der Handler ist eine Eigenschaft der Anwendungsinstanz: app.config.errorHandler = (err, instance, info) => { ... }. Er gehört zwischen createApp() und app.mount(). Der Vue-Guide ist bei der Reihenfolge deutlich: Alle App-Konfigurationen sollen vor dem Mounten der App gesetzt werden. Warum, zeigt sich hier gut, denn das erste Rendern und das setup() der Wurzelkomponente laufen beide beim Mounten.
Die Referenz nennt sieben Quellen, aus denen der Handler Fehler abfangen kann: das Rendern von Komponenten, Event-Handler, Lifecycle-Hooks, die Funktion setup(), Watcher, Hooks eigener Direktiven und Transition-Hooks. Diese Liste liest man am besten als Vertrag. Sie beschreibt Code, den Vue für dich aufruft. Code, über dem kein Vue-Aufruf im Stack liegt, ist ein anderes Thema und bekommt weiter unten einen eigenen Abschnitt.
Drei Argumente und die Falle im Produktionsbuild
Der Handler erhält drei Argumente. Das erste ist der Fehler, in der TypeScript-Signatur als unknown typisiert, weil JavaScript es erlaubt, alles Mögliche zu werfen: einen String, ein einfaches Objekt, undefined. Prüfe, ob es eine Error-Instanz ist, bevor du message oder stack liest. Das zweite ist die Komponenteninstanz, die den Fehler ausgelöst hat, oder null. Das dritte, info, ist ein Vue-spezifischer String, der die Art der Quelle benennt, zum Beispiel den Lifecycle-Hook, in dem der Fehler geworfen wurde.
- app.config.errorHandler erhält (err, instance, info) und wird vor app.mount() gesetzt
- Sieben dokumentierte Quellen: Rendern von Komponenten, Event-Handler, Lifecycle-Hooks, setup(), Watcher, Hooks eigener Direktiven, Transition-Hooks
- In Produktionsbuilds ist info ein kurzer Code; die Production Error Code Reference übersetzt ihn zurück in Text
- Standardverhalten: in der Entwicklung erneut werfen, in der Produktion in die Konsole schreiben; throwUnhandledErrorInProduction (3.5+) ändert das Zweite
- Ein onErrorCaptured()-Hook, der false zurückgibt, stoppt den Fehler vor dem globalen Handler
- Außerhalb von Vue: das error-Event auf window für synchrone Skriptfehler, unhandledrejection für Promises
Dieses dritte Argument hält eine Überraschung für alle bereit, die zum ersten Mal einen Bericht aus der Produktion öffnen. In Produktionsbuilds ist info ein verkürzter Code statt des vollständigen Strings. Die Vue-Dokumentation führt eine Seite namens Production Error Code Reference, die jeden Laufzeitcode wieder seinem ursprünglichen Text zuordnet. Sende den Rohwert so, wie er ankommt, und schlage ihn beim Lesen des Berichts nach. Logik, die info mit einem String aus der Entwicklung vergleicht, greift nach dem Build nicht mehr.
Entwicklung und Produktion verhalten sich unterschiedlich
Ohne Handler hängt Vues Verhalten vom Build ab. Laut Referenz wirft der Standard-Handler Fehler in der Entwicklung erneut und protokolliert sie in der Produktion. Die Entwicklungshälfte ist Absicht. Die Dokumentation sagt, der Fehler werde geworfen und könne die Anwendung möglicherweise zum Absturz bringen, damit er auffälliger ist und bemerkt und behoben wird.
Die Produktionshälfte hat eine Nebenwirkung, die für das Monitoring zählt. Ein Fehler, der nur in die Konsole geschrieben wird, wird nicht geworfen, und die Dokumentation merkt selbst an, dass Fehler, die nur in der Produktion auftreten, dadurch von Fehler-Monitoring-Diensten möglicherweise nicht erfasst werden. Seit Vue 3.5 gibt es dafür einen Schalter: app.config.throwUnhandledErrorInProduction, ein Boolean mit dem Standardwert false. Steht er auf true, werden unbehandelte Fehler auch im Produktionsmodus geworfen.
onErrorCaptured: lokale Grenzen vor dem globalen Handler
Der globale Handler ist die letzte Station. Davor kann jede Komponente Fehler aus ihren Nachfahren mit onErrorCaptured() abfangen, in der Options API mit errorCaptured. Der Hook erhält dieselben drei Argumente und ist das Werkzeug für eine Fehlergrenze: einen Zustand ändern, einen Ersatzinhalt rendern. Die Referenz hängt eine Warnung an. Der Fehlerzustand darf nicht den ursprünglichen Inhalt rendern, der den Fehler verursacht hat, sonst gerät die Komponente in eine endlose Render-Schleife.
Die Weitergabe folgt vier dokumentierten Regeln. Standardmäßig gehen abgefangene Fehler trotzdem an app.config.errorHandler, sofern er definiert ist, damit sie an einer einzigen Stelle gemeldet werden können. Liegen mehrere errorCaptured-Hooks auf der Elternkette, werden alle aufgerufen, von unten nach oben, ähnlich dem Bubbling von DOM-Events. Wirft ein Hook selbst einen Fehler, gehen dieser und der ursprüngliche an den globalen Handler. Und ein Hook kann false zurückgeben, um den Fehler dort zu stoppen: Für ihn wird dann weder ein weiterer Hook noch der globale Handler aufgerufen. Diese letzte Regel ist meist die Erklärung für einen Fehler, der auf dem Bildschirm einen Ersatzinhalt zeigt und in keinem Bericht auftaucht.
Was der globale Handler nie zu sehen bekommt
Nun zu dem Teil außerhalb des Vertrags. Ein Callback für setTimeout, ein von Hand mit addEventListener angehängter Listener, eine Promise-Kette aus einem Hilfsmodul, ein Skript eines Drittanbieters: Nichts davon gehört zu den sieben Quellen. Der Browser hat dafür zwei Events. Laut MDN wird das error-Event auf window ausgelöst, wenn eine Ressource nicht geladen oder nicht verwendet werden konnte, zum Beispiel wenn ein Skript einen Ausführungsfehler hat, und es entsteht nur für synchron geworfene Skriptfehler. Ein Promise, das ohne Rejection-Handler abgelehnt wird, wozu auch ein nicht abgefangenes throw in einer async-Funktion zählt, löst stattdessen unhandledrejection aus.
Ein vollständiges Setup hat deshalb drei Listener, die eine einzige Funktion speisen: app.config.errorHandler für den Code, den Vue aufruft, einen error-Listener auf window für synchrone Fehler an anderer Stelle und einen unhandledrejection-Listener für Promises, die niemand abgefangen hat. Fehlt einer davon, bleibt eine ganze Klasse von Fehlern unsichtbar.
Melden, ohne es schlimmer zu machen
Was die Funktion mit einem Fehler tut, entscheidet darüber, ob der Handler hilft. Halte sie klein und defensiv: den Fehler normalisieren, info, die aktuelle Route und die Release-Version anhängen und ihn dann an deinen Endpunkt senden. Umschließe den Rumpf mit try und catch, denn eine Meldefunktion, die selbst wirft, fügt dem ersten Fehler nur einen zweiten hinzu. Dedupliziere vor dem Senden, weil sich ein Renderfehler in einer Liste für jede Zeile wiederholen kann. Und behalte beim Entwickeln einen console.error-Aufruf im Handler: Sobald dein eigener installiert ist, läuft Vues Standard-Handler, der Fehler in der Entwicklung erneut wirft, nicht mehr.
Fehler beantworten eine einzige Frage: Was ist kaputtgegangen. Sie sagen nicht, wie lange der Nutzer davor gewartet hat oder welche Anfrage gerade unterwegs war. Das ist das Gebiet der Traces, behandelt in OpenTelemetry in einer Vue-App. Fang trotzdem mit dem Handler an. Er besteht aus wenigen Zeilen ohne jede Abhängigkeit und meldet die Probleme, nach denen du gar nicht gesucht hättest.
FAQ
Wo setzt man den globalen Error Handler in Vue 3?
Auf der Anwendungsinstanz, zwischen createApp() und app.mount(): app.config.errorHandler = (err, instance, info) => { ... }. Der Vue-Guide verlangt, alle App-Konfigurationen vor dem Mounten der App zu setzen.
Fängt app.config.errorHandler jeden Fehler auf der Seite ab?
Nein. Die Vue-Referenz nennt sieben Quellen: Rendern von Komponenten, Event-Handler, Lifecycle-Hooks, setup(), Watcher, Hooks eigener Direktiven und Transition-Hooks. Fehler außerhalb davon meldet der Browser, über das error-Event auf window für synchrone Skriptfehler und über unhandledrejection für Promises, die ohne Handler abgelehnt wurden.
Warum ist das Argument info in der Produktion ein Code statt eines lesbaren Strings?
In Produktionsbuilds übergibt Vue als drittes Argument von app.config.errorHandler und onErrorCaptured einen verkürzten Code. Die Production Error Code Reference in der Vue-Dokumentation ordnet jeden Laufzeitcode seinem ursprünglichen Informationsstring zu.
Was ist der Unterschied zwischen onErrorCaptured und app.config.errorHandler?
onErrorCaptured ist ein Komponenten-Hook, der Fehler aus Nachfahren-Komponenten abfängt und damit das Werkzeug für einen lokalen Ersatzinhalt ist. app.config.errorHandler gilt für die gesamte Anwendung und erhält diese Fehler standardmäßig trotzdem, sofern kein Hook false zurückgibt und die Weitergabe stoppt.



Ein vollständiges Setup hat deshalb drei Listener, die eine einzige Funktion speisen: app.config.errorHandler für den Code, den Vue aufruft, einen error-Listener auf window für synchrone Fehler an anderer Stelle und einen unhandledrejection-Listener für Promises, die niemand abgefangen hat. Fehlt einer davon, bleibt eine ganze Klasse von Fehlern unsichtbar.