Vue.js 3 runtime core library providing foundational APIs for building custom renderers and managing reactive component systems
—
Vue's error handling system provides utilities for graceful error management, including error capture, handling, and reporting mechanisms for building robust applications.
Handle errors with proper context and error information.
/**
* Handles errors with Vue's error handling pipeline
* @param err - Error to handle
* @param instance - Component instance where error occurred
* @param type - Error type for categorization
*/
function handleError(
err: unknown,
instance: ComponentInternalInstance | null,
type: ErrorTypes
): void;
/**
* Calls a function with error handling
* @param fn - Function to call
* @param instance - Component instance context
* @param type - Error type
* @param args - Arguments to pass to function
* @returns Function result or undefined on error
*/
function callWithErrorHandling<T extends any[], R>(
fn: (...args: T) => R,
instance: ComponentInternalInstance | null,
type: ErrorTypes,
args?: T
): R | undefined;
/**
* Calls async function(s) with error handling
* @param fn - Function or array of functions to call
* @param instance - Component instance context
* @param type - Error type
* @param args - Arguments to pass to function(s)
* @returns Promise resolving to results
*/
function callWithAsyncErrorHandling<T extends any[], R>(
fn: Function | Function[],
instance: ComponentInternalInstance | null,
type: ErrorTypes,
args?: T
): Promise<R[]>;Usage Examples:
import {
defineComponent,
handleError,
callWithErrorHandling,
callWithAsyncErrorHandling,
ErrorCodes
} from "@vue/runtime-core";
// Basic error handling
const SafeComponent = defineComponent({
setup() {
const riskyOperation = () => {
try {
// Some operation that might throw
JSON.parse('invalid json');
} catch (error) {
handleError(error, getCurrentInstance(), ErrorCodes.SETUP_FUNCTION);
}
};
// Safe function call with error handling
const safeFunctionCall = (userFunction: Function) => {
const result = callWithErrorHandling(
userFunction,
getCurrentInstance(),
ErrorCodes.COMPONENT_EVENT_HANDLER
);
console.log('Function result:', result);
};
return {
riskyOperation,
safeFunctionCall
};
}
});
// Async error handling
const AsyncErrorComponent = defineComponent({
setup() {
const handleAsyncOperations = async () => {
const asyncFunctions = [
async () => {
await fetch('/api/data1');
return 'data1';
},
async () => {
await fetch('/api/data2');
return 'data2';
},
async () => {
throw new Error('Intentional error');
}
];
const results = await callWithAsyncErrorHandling(
asyncFunctions,
getCurrentInstance(),
ErrorCodes.COMPONENT_EVENT_HANDLER
);
console.log('Async results:', results);
};
return {
handleAsyncOperations
};
}
});
// Error handling in lifecycle hooks
const LifecycleErrorComponent = defineComponent({
setup() {
onMounted(() => {
const initializeThirdPartyLib = () => {
// Third-party library initialization that might fail
window.ThirdPartyLib?.init({
apiKey: 'invalid-key'
});
};
callWithErrorHandling(
initializeThirdPartyLib,
getCurrentInstance(),
ErrorCodes.COMPONENT_EVENT_HANDLER
);
});
return {};
}
});Categorize errors for better handling and debugging.
/**
* Enumeration of error codes for different error types
*/
enum ErrorCodes {
SETUP_FUNCTION = 'setup function',
RENDER_FUNCTION = 'render function',
WATCH_GETTER = 'watcher getter',
WATCH_CALLBACK = 'watcher callback',
WATCH_CLEANUP = 'watcher cleanup function',
NATIVE_EVENT_HANDLER = 'native event handler',
COMPONENT_EVENT_HANDLER = 'component event handler',
VNODE_HOOK = 'vnode hook',
DIRECTIVE_HOOK = 'directive hook',
TRANSITION_HOOK = 'transition hook',
APP_ERROR_HANDLER = 'app errorHandler',
APP_WARN_HANDLER = 'app warnHandler',
FUNCTION_REF = 'ref function',
ASYNC_COMPONENT_LOADER = 'async component loader',
SCHEDULER = 'scheduler flush'
}
type ErrorTypes = ErrorCodes | string;Usage Examples:
// Custom error handling by type
const createErrorHandler = () => {
const errorCounts = reactive<Record<string, number>>({});
const customHandleError = (
err: unknown,
instance: ComponentInternalInstance | null,
type: ErrorTypes
) => {
// Track error frequency
if (typeof type === 'string') {
errorCounts[type] = (errorCounts[type] || 0) + 1;
}
// Different handling based on error type
switch (type) {
case ErrorCodes.RENDER_FUNCTION:
console.error('Render error - component may be broken:', err);
break;
case ErrorCodes.ASYNC_COMPONENT_LOADER:
console.warn('Async component failed to load:', err);
break;
case ErrorCodes.NATIVE_EVENT_HANDLER:
console.error('Native event handler error:', err);
break;
default:
console.error(`Error in ${type}:`, err);
}
// Use Vue's default error handling
handleError(err, instance, type);
};
return {
customHandleError,
errorCounts: readonly(errorCounts)
};
};
// Error boundary component
const ErrorBoundary = defineComponent({
setup(_, { slots }) {
const hasError = ref(false);
const error = ref<Error | null>(null);
onErrorCaptured((err, instance, info) => {
hasError.value = true;
error.value = err instanceof Error ? err : new Error(String(err));
// Log error with context
handleError(err, instance, `error boundary: ${info}`);
// Prevent error from propagating
return false;
});
const retry = () => {
hasError.value = false;
error.value = null;
};
return () => {
if (hasError.value) {
return h('div', { class: 'error-boundary' }, [
h('h3', 'Something went wrong'),
h('p', error.value?.message || 'Unknown error'),
h('button', { onClick: retry }, 'Retry')
]);
}
return slots.default?.();
};
}
});Warning and development utilities for debugging.
/**
* Development warning utility (only in development mode)
* @param msg - Warning message
* @param args - Additional arguments to log
*/
declare const warn: (msg: string, ...args: any[]) => void;
/**
* Assert that a value is a number (development only)
* @param val - Value to check
* @param type - Context type for error message
*/
function assertNumber(val: unknown, type: string): void;Usage Examples:
import { warn, assertNumber } from "@vue/runtime-core";
const ValidationComponent = defineComponent({
props: {
count: [Number, String],
timeout: Number
},
setup(props) {
// Development warnings
if (__DEV__) {
if (typeof props.count === 'string') {
warn('count prop should be a number, received string:', props.count);
}
// Assert number type
if (props.timeout !== undefined) {
assertNumber(props.timeout, 'timeout prop');
}
}
const processCount = () => {
const numericCount = typeof props.count === 'string'
? parseInt(props.count, 10)
: props.count || 0;
if (__DEV__ && isNaN(numericCount)) {
warn('Invalid count value, defaulting to 0');
}
return isNaN(numericCount) ? 0 : numericCount;
};
return {
processCount
};
}
});
// Custom validation with warnings
const useValidation = () => {
const validateProps = (props: Record<string, any>, schema: Record<string, any>) => {
for (const [key, validator] of Object.entries(schema)) {
const value = props[key];
if (validator.required && (value === undefined || value === null)) {
if (__DEV__) {
warn(`Required prop "${key}" is missing`);
}
continue;
}
if (value !== undefined && validator.type && typeof value !== validator.type) {
if (__DEV__) {
warn(`Prop "${key}" expected ${validator.type}, got ${typeof value}`);
}
}
if (validator.validator && !validator.validator(value)) {
if (__DEV__) {
warn(`Prop "${key}" failed custom validation`);
}
}
}
};
return { validateProps };
};// Global error handler setup
const setupGlobalErrorHandling = (app: App) => {
app.config.errorHandler = (err, instance, info) => {
// Custom global error handling
console.error('Global error:', err);
console.log('Component:', instance);
console.log('Error info:', info);
// Send to error reporting service
sendErrorToService(err, {
component: instance?.type?.name || 'Unknown',
info,
stack: err instanceof Error ? err.stack : undefined
});
// Use Vue's error handling
handleError(err, instance, `global handler: ${info}`);
};
app.config.warnHandler = (msg, instance, trace) => {
console.warn('Vue warning:', msg);
if (instance) {
console.log('Component:', instance.type?.name);
}
console.log('Trace:', trace);
};
};
// Error recovery utilities
const useErrorRecovery = () => {
const retryCount = ref(0);
const maxRetries = 3;
const withRetry = async <T>(
operation: () => Promise<T>,
errorType: ErrorTypes = ErrorCodes.COMPONENT_EVENT_HANDLER
): Promise<T | null> => {
try {
const result = await callWithAsyncErrorHandling(
[operation],
getCurrentInstance(),
errorType
);
retryCount.value = 0; // Reset on success
return result[0];
} catch (error) {
retryCount.value++;
if (retryCount.value < maxRetries) {
console.log(`Retrying operation (${retryCount.value}/${maxRetries})`);
return withRetry(operation, errorType);
}
console.error('Max retries exceeded');
return null;
}
};
return {
withRetry,
retryCount: readonly(retryCount)
};
};
// Circuit breaker pattern
class CircuitBreaker {
private failures = 0;
private lastFailureTime = 0;
private state: 'closed' | 'open' | 'half-open' = 'closed';
constructor(
private failureThreshold = 5,
private recoveryTimeout = 30000
) {}
async execute<T>(
operation: () => Promise<T>,
fallback?: () => T
): Promise<T> {
if (this.state === 'open') {
if (Date.now() - this.lastFailureTime > this.recoveryTimeout) {
this.state = 'half-open';
} else {
if (fallback) return fallback();
throw new Error('Circuit breaker is open');
}
}
try {
const result = await callWithAsyncErrorHandling(
[operation],
null,
ErrorCodes.COMPONENT_EVENT_HANDLER
);
// Success - reset circuit breaker
if (this.state === 'half-open') {
this.state = 'closed';
this.failures = 0;
}
return result[0];
} catch (error) {
this.failures++;
this.lastFailureTime = Date.now();
if (this.failures >= this.failureThreshold) {
this.state = 'open';
}
if (fallback) return fallback();
throw error;
}
}
}enum ErrorCodes {
SETUP_FUNCTION = 'setup function',
RENDER_FUNCTION = 'render function',
WATCH_GETTER = 'watcher getter',
WATCH_CALLBACK = 'watcher callback',
WATCH_CLEANUP = 'watcher cleanup function',
NATIVE_EVENT_HANDLER = 'native event handler',
COMPONENT_EVENT_HANDLER = 'component event handler',
VNODE_HOOK = 'vnode hook',
DIRECTIVE_HOOK = 'directive hook',
TRANSITION_HOOK = 'transition hook',
APP_ERROR_HANDLER = 'app errorHandler',
APP_WARN_HANDLER = 'app warnHandler',
FUNCTION_REF = 'ref function',
ASYNC_COMPONENT_LOADER = 'async component loader',
SCHEDULER = 'scheduler flush'
}
type ErrorTypes = ErrorCodes | string;
interface ErrorHandler {
(err: unknown, instance: ComponentInternalInstance | null, info: string): void;
}
interface WarnHandler {
(msg: string, instance: ComponentInternalInstance | null, trace: string): void;
}onErrorCaptured to contain errors within components// Development-only error handling
if (__DEV__) {
warn('This is a development warning');
assertNumber(value, 'prop name');
}
// Production error handling
const handleProductionError = (error: unknown) => {
// Log to service, show user-friendly message
console.error('An error occurred');
// Don't expose internal details
};Install with Tessl CLI
npx tessl i tessl/npm-vue--runtime-core