Error Boundaries in Vue & Nuxt
Fehler in Vue-Anwendungen, die den kompletten Komponentenbaum zum Absturz bringen, sind vermeidbar. onErrorCaptured, der globale errorHandler, error.vue und NuxtErrorBoundary bilden ein mehrschichtiges System, das Fehler isoliert, sinnvolle Fallbacks zeigt und den Rest der Anwendung am Leben hält.
Inhaltsverzeichnis
- 1. Warum Error Boundaries in Vue unverzichtbar sind
- 2. onErrorCaptured: die lokale Error Boundary
- 3. Fallback-UI: Fehler sichtbar machen ohne Absturz
- 4. Globaler errorHandler: letzte Auffanglinie
- 5. error.vue in Nuxt 3: Fehlerseiten auf Routenebene
- 6. NuxtErrorBoundary: granulare Fehlerisolation
- 7. Asynchrone Fehler und useAsyncData
- 8. Fehler-Monitoring und Sentry-Integration
- 9. Vergleich der Fehlerbehandlungsebenen
- 10. Zusammenfassung
- 11. FAQ
1. Warum Error Boundaries in Vue unverzichtbar sind
Eine Vue-Anwendung ohne durchdachte Error Boundaries verhält sich bei einem unbehandelten Laufzeitfehler wie ein Kartenhaus: Eine einzelne Komponente, die beim Rendern eine Exception wirft, kann den gesamten Komponentenbaum unmounten und dem Nutzer eine weiße Seite oder eine generische Browserkonsolen-Meldung hinterlassen. Das ist in einer Produktionsanwendung inakzeptabel – besonders wenn der Fehler in einer Seitenleiste oder einem Widget aufgetreten ist, das nichts mit dem Hauptinhalt zu tun hat.
Vue 3 hat dieses Problem erkannt und bietet mit onErrorCaptured einen Lifecycle-Hook, der Fehler aus der eigenen Komponente und allen Kindkomponenten abfangen kann, bevor sie den Rest der Anwendung beschädigen. In Kombination mit dem globalen app.config.errorHandler, dem Nuxt-spezifischen error.vue und der NuxtErrorBoundary-Komponente entsteht ein mehrschichtiges Sicherheitsnetz, das Fehler isoliert, protokolliert und dem Nutzer eine kontextbezogene Rückmeldung gibt. Wer Error Boundaries in Vue konsequent einsetzt, reduziert Support-Anfragen und verbessert messbar das Nutzererlebnis bei unvermeidlichen Fehlerszenarien.
2. onErrorCaptured: die lokale Error Boundary
onErrorCaptured ist der Kern jeder lokalen Error Boundary in Vue 3. Der Hook wird in der Elternkomponente registriert und erhält drei Parameter: den aufgetretenen Fehler, die Komponenteninstanz, in der er aufgetreten ist, und einen String mit dem Fehlerursprung (z.B. "render", "setup function" oder "watcher"). Gibt der Hook false zurück, wird der Fehler nicht weiter nach oben propagiert – die Elternkomponenten und der globale Handler bekommen ihn nicht zu sehen. Wird nichts oder undefined zurückgegeben, propagiert der Fehler nach oben, bis er entweder von einer anderen Elternkomponente oder vom globalen Handler aufgefangen wird.
Das typische Muster für eine Error Boundary-Komponente in Vue 3 nutzt onErrorCaptured zusammen mit einem reaktiven hasError-State, um zwischen normalem Slot-Inhalt und einem Fallback-UI zu wechseln. Wichtig: Der Hook fängt nur Fehler aus synchronem Rendering, Lifecycle-Hooks und Watchers. Fehler in asynchronen Event-Handlern, die außerhalb des Vue-Lifecycle-Kontexts geworfen werden, müssen separat behandelt werden. Diese Einschränkung ist kein Bug, sondern eine bewusste Designentscheidung, die das Verhalten von Error Boundaries in Vue vorhersagbar hält.
<!-- ErrorBoundary.vue — reusable error boundary component -->
<template>
<slot v-if="!hasError" />
<slot v-else name="fallback" :error="capturedError" :reset="resetError">
<div class="error-boundary-fallback">
<p>Ein Fehler ist aufgetreten.</p>
<button @click="resetError">Neu laden</button>
</div>
</slot>
</template>
<script setup>
import { ref, onErrorCaptured } from 'vue'
const hasError = ref(false)
const capturedError = ref(null)
// Capture errors from all child components
onErrorCaptured((err, instance, info) => {
hasError.value = true
capturedError.value = err
console.error('[ErrorBoundary] caught error:', err.message, 'in', info)
// Return false to stop error propagation
return false
})
function resetError() {
hasError.value = false
capturedError.value = null
}
<\/script>
3. Fallback-UI: Fehler sichtbar machen ohne Absturz
Eine gute Fallback-UI für eine Vue Error Boundary kommuniziert dem Nutzer klar, dass etwas schief gelaufen ist, ohne ihn mit technischen Details zu überfordern. Das Minimalziel: Der Nutzer versteht, was nicht funktioniert hat, kann entweder eine Aktion unternehmen (neu laden, zurück navigieren) oder weiß, dass der Rest der Anwendung weiterhin nutzbar ist. Eine Fallback-UI für eine Produktliste sollte nicht den gesamten Shop sperren, sondern nur das betroffene Widget ersetzen.
Das Named-Slot-Muster der ErrorBoundary-Komponente aus dem vorherigen Abschnitt erlaubt es, pro Verwendungsstelle eine spezifische Fallback-UI zu definieren. Die Wrapper-Komponente kann dabei genauso viel oder wenig über den Fehler preisgeben, wie es der Kontext erlaubt: In der Entwicklungsumgebung zeigt man den Stack-Trace, in der Produktion eine benutzerfreundliche Nachricht mit Fehler-ID. Die Fehler-ID, die man aus dem Monitoring-System zurückbekommt, gibt dem Support-Team sofort den Kontext, den sie brauchen. Dieser Ansatz mit Error Boundaries in Vue macht Fehlermeldungen sowohl nutzbar als auch debugbar.
4. Globaler errorHandler: letzte Auffanglinie
Nicht jede Komponente wird von einer lokalen Error Boundary umschlossen. Für alle Fehler, die keinen lokalen Handler finden, gibt es app.config.errorHandler. Dieser globale Handler wird in main.js bzw. in einem Nuxt-Plugin registriert und erhält dieselben Parameter wie onErrorCaptured: Fehler, Komponente und Fehlerursprung. Er ist die letzte Möglichkeit, einen Fehler zu protokollieren, bevor Vue ihn an die Browserkonsole weitergibt.
Ein gut strukturierter globaler errorHandler unterscheidet zwischen kritischen Fehlern, die eine Seite unbrauchbar machen, und tolerierbaren Fehlern, die nur ein Widget betreffen. Er sendet strukturierte Fehlerinformationen an ein externes Monitoring-System wie Sentry, LogRocket oder einen eigenen Logging-Endpoint und zeigt bei kritischen Fehlern eine seitenweite Fehleranzeige. In Nuxt 3 ersetzt man diesen Handler teilweise durch Nuxt-eigene Mechanismen, aber als Fallback für Vue-interne Fehler bleibt er unersetzlich. Wer den globalen errorHandler nicht konfiguriert, verliert wertvolle Fehlerdaten aus der Produktion.
// plugins/error-handler.client.js — Nuxt 3 plugin for global error handling
export default defineNuxtPlugin((nuxtApp) => {
// Global Vue error handler — catches all unhandled component errors
nuxtApp.vueApp.config.errorHandler = (error, instance, info) => {
const componentName = instance?.$options?.name ?? 'unknown'
// Log structured error data
console.error('[GlobalErrorHandler]', {
message: error.message,
component: componentName,
lifecycleHook: info,
stack: error.stack,
})
// Send to monitoring (e.g. Sentry)
if (typeof $sentry !== 'undefined') {
$sentry.captureException(error, {
extra: { component: componentName, vueInfo: info },
})
}
}
// Catch unhandled promise rejections outside Vue lifecycle
if (import.meta.client) {
window.addEventListener('unhandledrejection', (event) => {
console.error('[UnhandledPromise]', event.reason)
})
}
})
5. error.vue in Nuxt 3: Fehlerseiten auf Routenebene
Nuxt 3 bringt mit error.vue im Projektstamm eine eigene Mechanik für Fehlerseiten auf Routenebene. Diese Komponente wird automatisch angezeigt, wenn Nuxt selbst einen fatalen Fehler feststellt – etwa einen 404, einen 500 vom Server oder einen Fehler während des Server-Side Renderings. Die Komponente erhält das error-Prop mit statusCode, statusMessage und message. Mit useError() hat man Zugriff auf den aktuellen Fehlerstatus aus jeder Komponente heraus, und clearError() setzt den Fehlerstatus zurück und navigiert optional auf eine andere Route.
Ein häufiger Fehler beim Einsatz von error.vue: Man behandelt alle Statuscodes gleich und zeigt immer dieselbe Nachricht. Besser ist es, für 404 eine Suche oder verwandte Inhalte anzubieten, bei 500 eine Support-Kontaktmöglichkeit und bei Netzwerkfehlern einen Retry-Button. Nuxt 3 ermöglicht das sauber über den error.statusCode im Template. Die error.vue ist bewusst keine Layout-Komponente – sie wird außerhalb des normalen Nuxt-Layouts gerendert. Wer das Hauptlayout trotzdem einbinden möchte, muss es explizit in error.vue importieren und verwenden.
6. NuxtErrorBoundary: granulare Fehlerisolation
NuxtErrorBoundary ist die Nuxt-eigene Implementierung einer Error Boundary, die über die globale error.vue hinausgeht. Sie ermöglicht es, einzelne Sektionen einer Seite gegen Fehler abzusichern, ohne dass die gesamte Seite auf die Fehlerseite umspringt. Der @error-Event-Handler empfängt den Fehler und ermöglicht lokale Reaktionen. Der #error-Slot zeigt die Fallback-UI innerhalb der Boundary. Mit clearError aus dem Slot-Scope lässt sich der Fehlerstauts zurücksetzen, ohne die Seite neu zu laden.
In der Praxis eignet sich NuxtErrorBoundary besonders für Widgets, die Daten von externen APIs laden. Schlägt die API-Anfrage fehl, zeigt die Boundary eine Fehlermeldung nur für diesen Bereich – der Rest der Seite, inklusive Navigation und anderer Widgets, bleibt funktionsfähig. Diese Granularität ist der entscheidende Unterschied zu einer seitenweiten Fehlerseite. Wer NuxtErrorBoundary konsequent einsetzt, schafft eine Anwendung, die auch bei Teilausfällen externer Dienste für den Nutzer nutzbar bleibt.
<!-- pages/dashboard.vue — granular error isolation with NuxtErrorBoundary -->
<template>
<div class="dashboard-grid">
<NuxtErrorBoundary @error="onWidgetError">
<WeatherWidget />
<template #error="{ error, clearError }">
<div class="widget-error">
<p>Wetterdaten nicht verfügbar.</p>
<button @click="clearError()">Erneut versuchen</button>
</div>
</template>
</NuxtErrorBoundary>
<NuxtErrorBoundary @error="onWidgetError">
<StockTickerWidget />
<template #error="{ error, clearError }">
<div class="widget-error">
<p>Kursdaten nicht verfügbar.</p>
<button @click="clearError()">Erneut versuchen</button>
</div>
</template>
</NuxtErrorBoundary>
</div>
</template>
<script setup>
// Centralized widget error tracking
function onWidgetError(error) {
console.warn('[Dashboard] Widget-Fehler abgefangen:', error.message)
// Report to monitoring without crashing the page
}
<\/script>
7. Asynchrone Fehler und useAsyncData
Asynchrone Datenfehler sind in Nuxt 3 die häufigste Quelle für schlechte Nutzererfahrungen. useAsyncData und useFetch geben bei einem fehlgeschlagenen Fetch kein Promise zurück, das unbehandelt bleibt – stattdessen landen Fehlerinformationen in der error-Ref, die die Composable zurückgibt. Das ermöglicht deklaratives Fehlerhandling direkt im Template, ohne try-catch-Blöcke. Die status-Ref mit den Werten "idle", "pending", "success" und "error" macht den Zustand der Datenanfrage jederzeit abfragbar.
Ein kritischer Unterschied: Wenn useAsyncData auf dem Server fehlschlägt und error nicht behandelt wird, löst Nuxt automatisch die error.vue aus. Wer das verhindern will, muss entweder { server: false } setzen oder den Fehler lokal behandeln und clearError() aufrufen. Das Muster, Fehler aus useAsyncData mit einer lokalen Error Boundary zu kombinieren, gibt volle Kontrolle: Server-Fehler werden durch error.vue aufgefangen, Client-seitige Fetch-Fehler nach der Hydration durch NuxtErrorBoundary. Dieses mehrschichtige Fehlerhandling ist der Schlüssel zu robustem Error Boundary-Design in Nuxt.
8. Fehler-Monitoring und Sentry-Integration
Fehlerbehandlung ohne Monitoring ist blind. Eine Error Boundary in Vue, die Fehler stillschweigend wegwirft, ohne sie zu protokollieren, schafft ein falsches Sicherheitsgefühl. Sentry ist das verbreitetste Monitoring-Tool für Vue- und Nuxt-Anwendungen und lässt sich über das offizielle Nuxt-Modul @sentry/nuxt integrieren. Nach der Integration fängt Sentry automatisch alle unbehandelten Fehler ab, inklusive Source-Map-Deobfuskation für minifizierten Code. Man sieht exakt, in welcher Zeile des Originalcodes der Fehler aufgetreten ist.
In der Kombination mit Error Boundaries ergibt sich ein klares Reporting-Muster: Fehler, die von einer lokalen Boundary abgefangen werden, werden manuell via Sentry.captureException() gemeldet und als "handled" markiert. Fehler, die durch alle Grenzen fallen und vom globalen Handler oder Nuxt-System aufgefangen werden, landen als "unhandled" in Sentry. Diese Unterscheidung gibt dem Team sofort Priorität: "unhandled" Fehler sind kritisch und gehören sofort behoben, "handled" Fehler sind bekannte Randfälle, die überwacht werden sollten. Wer Error Boundaries in Vue und Nuxt ohne dieses Monitoring einsetzt, verschenkt den wertvollsten Teil: das Wissen, welche Fehler in der Produktion tatsächlich auftreten.
9. Vergleich der Fehlerbehandlungsebenen
Vue 3 und Nuxt 3 bieten verschiedene Mechanismen für Error Boundaries und Fehlerbehandlung, die sich in Reichweite, Granularität und Anwendungsfall unterscheiden. Die Wahl des richtigen Mechanismus hängt davon ab, wie viel des UI-Baums isoliert werden soll und ob es sich um einen Fehler in der Render-Phase, einem Lifecycle-Hook oder einer asynchronen Datenfetchung handelt.
| Mechanismus | Ebene | Fängt ab | Empfohlener Einsatz |
|---|---|---|---|
| onErrorCaptured | Komponente | Render, Lifecycle, Watcher | Widget-Level Isolation |
| app.config.errorHandler | Anwendung | Alle unkatasierten Fehler | Monitoring & Logging |
| error.vue (Nuxt) | Route / Seite | 404, 500, SSR-Fehler | Fatale Seitenfehler |
| NuxtErrorBoundary | Sektion | Async-Fehler im Slot | Granulare Fehlerisolation |
| useFetch error-Ref | Composable | HTTP- und Netzwerkfehler | Deklaratives Datenfehler-Handling |
In der Praxis kombiniert man alle fünf Mechanismen. Ein typisches Setup: NuxtErrorBoundary für API-abhängige Widgets, onErrorCaptured in kritischen Elternkomponenten für Render-Fehler, error.vue als Seiten-Fallback für unbekannte Routen und Server-Fehler, und app.config.errorHandler als universeller Logging-Hook. Diese Schichtung stellt sicher, dass kein Fehler unbemerkt bleibt und gleichzeitig der kleinstmögliche Teil der Anwendung für den Nutzer ausfällt.
Mironsoft
Vue 3- und Nuxt 3-Entwicklung mit robuster Fehlerbehandlung
Vue-Anwendungen, die auch bei Fehlern nutzbar bleiben?
Wir analysieren bestehende Vue- und Nuxt-Projekte auf fehlende Error Boundaries, implementieren granulare Fehlerisolation und integrieren Monitoring, das Produktionsfehler sichtbar macht – bevor Nutzer sie melden.
Fehleranalyse
Audit bestehender Vue-Anwendungen auf fehlende Error Boundaries und unbehandelte Async-Fehler
Implementierung
Saubere Error Boundary-Architektur mit NuxtErrorBoundary, onErrorCaptured und error.vue
Monitoring
Sentry-Integration mit Source Maps, strukturiertem Logging und Fehler-Priorisierung
10. Zusammenfassung
Robuste Error Boundaries in Vue und Nuxt sind kein Luxus, sondern Grundvoraussetzung für produktionsreife Anwendungen. onErrorCaptured isoliert Fehler auf Komponentenebene und verhindert, dass ein Widget-Fehler die gesamte Seite zerstört. Der globale app.config.errorHandler ist die letzte Auffanglinie für alle Fehler, die keine lokale Boundary haben, und der richtige Ort für strukturiertes Logging und Monitoring-Integration. In Nuxt 3 ergänzen error.vue für fatale Seitenfehler und NuxtErrorBoundary für granulare Sektionsisolation das Bild.
Das Zusammenspiel dieser Mechanismen schafft ein mehrschichtiges Sicherheitsnetz: Fehler werden auf der niedrigstmöglichen Ebene abgefangen, dem Nutzer wird eine kontextbezogene Fallback-UI präsentiert, und das Team bekommt über das Monitoring die Informationen, die es für eine schnelle Diagnose braucht. Wer heute Error Boundaries in Vue implementiert, investiert in Nutzerzufriedenheit und Support-Effizienz gleichzeitig.
Error Boundaries in Vue & Nuxt — Das Wichtigste auf einen Blick
Lokale Isolation
onErrorCaptured in Elternkomponenten fängt Render- und Lifecycle-Fehler aus dem gesamten Kindbaum ab. Rückgabe von false stoppt Propagation.
Globales Logging
app.config.errorHandler ist die letzte Auffanglinie – ideal für Sentry-Integration und strukturiertes Fehler-Monitoring in der Produktion.
Nuxt-Ebenen
error.vue für fatale Seitenfehler (404, 500, SSR). NuxtErrorBoundary für granulare Widget-Isolation ohne Seitenwechsel.
Async-Fehler
useFetch und useAsyncData liefern Fehler in einer Ref – deklarativ im Template behandelbar, ohne try-catch in der Komponente.