Vue 3 Error Capturing and Fallback Strategies
Implement production-grade error isolation and graceful degradation in Vue 3 applications. This guide details component-level error boundaries, global Vue error handlers, and fallback rendering strategies. It builds upon foundational Core JavaScript Error Handling & Boundaries principles to ensure resilient frontend architectures.
Key Implementation Points:
- Configure
app.config.errorHandlerfor centralized telemetry routing - Implement
onErrorCapturedfor localized component subtree isolation - Design state-driven fallback UI components with automatic recovery
- Integrate Vite hidden source maps for accurate production stack resolution
- Handle async composable failures without triggering unhandled promise crashes
Global Vue Error Handler Configuration
Establish a centralized error routing mechanism that intercepts synchronous Vue rendering errors. Forward them to observability platforms without blocking the main thread.
Register app.config.errorHandler using the (err, instance, info) => void signature. Filter framework-specific warnings from production telemetry payloads. Prevent error swallowing by conditionally re-throwing after logging. This approach aligns with Mastering window.onerror and Global Event Listeners for cross-boundary coverage.
import { createApp } from 'vue';
import { trackError } from './telemetry';
const app = createApp(App);
app.config.errorHandler = (err, instance, info) => {
const component = instance?.$.type?.name || 'Unknown';
trackError(err, { component, info, timestamp: Date.now() });
if (process.env.NODE_ENV === 'development') {
console.error('[Vue Global Handler]', err);
}
};
app.mount('#app');
This demonstrates centralized error interception, component name extraction, and environment-aware logging. It routes telemetry without blocking execution.
Component-Level Error Boundaries with onErrorCaptured
Isolate failures to specific component subtrees. Prevent cascading UI crashes by intercepting errors before they reach the global handler.
Use the onErrorCaptured composition API hook for localized interception. Return false to halt error propagation to parent boundaries. Maintain component state consistency during partial render failures. Implement fallback slot rendering based on captured error metadata.
import { ref, onErrorCaptured } from 'vue';
export function useErrorBoundary() {
const error = ref(null);
const hasError = ref(false);
onErrorCaptured((err, instance, info) => {
error.value = err;
hasError.value = true;
return false; // Stops propagation to parent
});
return { error, hasError, reset: () => { error.value = null; hasError.value = false; } };
}
This shows localized error state management, propagation halting, and reset functionality for component-level recovery workflows.
Async Composable and Promise Rejection Handling
Capture unhandled promise rejections originating from Vue composables, lifecycle hooks, and router guards. Prevent them from escaping the Vue runtime.
Wrap async composables in try/catch with explicit fallback reactive states. Attach .catch() handlers to onMounted and onBeforeMount async operations. Map rejected promises to Vue reactive error flags for conditional rendering. Integrate with Handling Unhandled Promise Rejections in Modern JS for runtime parity.
import { ref, onMounted } from 'vue';
export function useAsyncData(fetcher) {
const data = ref(null);
const loading = ref(false);
const error = ref(null);
const execute = async () => {
loading.value = true;
error.value = null;
try {
data.value = await fetcher();
} catch (err) {
error.value = err;
data.value = null;
} finally {
loading.value = false;
}
};
onMounted(execute);
return { data, loading, error, retry: execute };
}
This illustrates safe async execution within Vue composables, explicit error state assignment, and retry capability without triggering unhandled promise rejections.
Source Map Integration and Stack Trace Reconstruction
Configure build tooling to generate accurate source maps for minified production bundles. Ensure telemetry platforms can deobfuscate stack traces.
Enable build.sourcemap: 'hidden' in Vite configuration for secure uploads. Configure Sentry CLI or equivalent to upload maps during CI/CD pipelines. Validate stack trace deobfuscation using local source-map-explorer. Map Vue component names to minified function identifiers via the devtools flag.
// vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
build: {
sourcemap: 'hidden',
minify: 'terser',
rollupOptions: {
output: {
sourcemapExcludeSources: false
}
}
}
});
This configures Vite to generate source maps without exposing them publicly. It enables secure CI/CD upload to observability platforms while preserving debug fidelity.
Fallback UI Rendering Strategies
Design resilient UI patterns that gracefully degrade when component trees fail. Ensure core application functionality remains accessible.
Implement error boundary wrapper components with scoped fallback slots. Use v-if/v-else for state-driven error recovery and retry triggers. Cache last-known-good state for critical data grids and form inputs. Trigger automatic retry logic with exponential backoff and circuit breakers.
Common Mistakes
- Swallowing errors in
app.config.errorHandlerwithout re-throwing: Silently consuming errors prevents Vue from triggering fallback UI states. It breaks observability chain integrity, leading to silent UI corruption. - Returning
truefromonErrorCaptured: Returningtruesignals Vue to continue propagating the error upward. This defeats component-level isolation and causes duplicate telemetry events. - Exposing public source maps in production: Serving
.mapfiles publicly exposes unminified source code, proprietary logic, and internal API endpoints to malicious actors. - Ignoring async composable rejections in
setup(): Uncaught promises insetup()bypass Vue’s synchronous error boundaries. They triggerunhandledRejectionevents, requiring separate runtime interception.
Frequently Asked Questions
How does Vue 3 error handling differ from React Error Boundaries?
Vue uses app.config.errorHandler and onErrorCaptured hooks instead of class-based componentDidCatch. It offers composition API integration and automatic propagation control via return values.
Should I re-throw errors in app.config.errorHandler?
Yes. Re-throwing ensures Vue’s internal fallback mechanisms activate. It prevents silent state corruption while telemetry platforms still capture the initial interception.
How do I handle async errors in Vue 3 setup functions?
Wrap async operations in try/catch. Map failures to reactive error states. Attach .catch() handlers to onMounted promises to prevent unhandledRejection events.
What is the optimal Vite config for production source maps?
Use build.sourcemap: 'hidden' to generate maps without public exposure. Upload them securely via CI/CD pipelines using Sentry CLI or equivalent tooling.