Rich JavaScript errors with printf-style messages, error chaining, and structured metadata
—
VError provides a comprehensive set of static utility methods for error analysis, cause traversal, and error manipulation. These methods work with any Error objects, not just VError instances, making them useful for analyzing errors throughout your application.
Retrieves the cause of any Error object, returning null if no cause exists.
/**
* Get the cause of any Error object
* @param {Error} err - Error to inspect (must be an Error instance)
* @returns {Error|null} Cause error or null if no cause exists
*/
VError.cause(err);Usage Examples:
const VError = require('verror');
const originalError = new Error('file not found');
const chainedError = new VError(originalError, 'failed to read config');
console.log(VError.cause(chainedError) === originalError); // true
console.log(VError.cause(originalError)); // null (no cause)
// Works with any Error, not just VError
const regularError = new Error('regular error');
console.log(VError.cause(regularError)); // nullRetrieves accumulated info properties from the entire error cause chain. Properties from deeper causes are overridden by properties from errors higher in the chain.
/**
* Get accumulated info properties from entire error chain
* @param {Error} err - Error to inspect (must be an Error instance)
* @returns {Object} Merged info properties from cause chain (deeper causes first)
*/
VError.info(err);Usage Examples:
const VError = require('verror');
// Build error chain with info
const dbError = new VError({
info: {
host: 'db.example.com',
port: 5432,
database: 'users'
}
}, 'database connection failed');
const serviceError = new VError({
cause: dbError,
info: {
service: 'user-service',
operation: 'fetch-user',
port: 3000 // This overrides the port from dbError
}
}, 'service operation failed');
const info = VError.info(serviceError);
console.log(info);
// {
// host: 'db.example.com', // from dbError
// port: 3000, // from serviceError (overrides dbError.port)
// database: 'users', // from dbError
// service: 'user-service', // from serviceError
// operation: 'fetch-user' // from serviceError
// }
// Works with regular errors (returns empty object)
const regularError = new Error('regular error');
console.log(VError.info(regularError)); // {}Searches through the error cause chain to find the first error with a specific name.
/**
* Find first error in cause chain with specific name
* @param {Error} err - Error to search from (must be an Error instance)
* @param {string} name - Error name to find (must be non-empty string)
* @returns {Error|null} First matching error or null if not found
*/
VError.findCauseByName(err, name);Usage Examples:
const VError = require('verror');
// Create error chain with named errors
const dbError = new VError({ name: 'DatabaseError' }, 'connection failed');
const authError = new VError({
name: 'AuthenticationError',
cause: dbError
}, 'auth failed');
const apiError = new VError({
name: 'APIError',
cause: authError
}, 'request failed');
// Find specific errors in the chain
const foundDb = VError.findCauseByName(apiError, 'DatabaseError');
console.log(foundDb === dbError); // true
const foundAuth = VError.findCauseByName(apiError, 'AuthenticationError');
console.log(foundAuth === authError); // true
const notFound = VError.findCauseByName(apiError, 'NotFoundError');
console.log(notFound); // null
// Search from any point in the chain
const fromAuth = VError.findCauseByName(authError, 'DatabaseError');
console.log(fromAuth === dbError); // trueChecks if the error cause chain contains an error with a specific name.
/**
* Check if cause chain contains error with specific name
* @param {Error} err - Error to search from (must be an Error instance)
* @param {string} name - Error name to find (must be non-empty string)
* @returns {boolean} True if error with given name exists in cause chain
*/
VError.hasCauseWithName(err, name);Usage Examples:
const VError = require('verror');
const dbError = new VError({ name: 'DatabaseError' }, 'connection failed');
const authError = new VError({
name: 'AuthenticationError',
cause: dbError
}, 'auth failed');
// Check for specific error types
console.log(VError.hasCauseWithName(authError, 'DatabaseError')); // true
console.log(VError.hasCauseWithName(authError, 'AuthenticationError')); // true
console.log(VError.hasCauseWithName(authError, 'NetworkError')); // false
// Useful for error handling logic
function handleError(err) {
if (VError.hasCauseWithName(err, 'DatabaseError')) {
console.log('Database issue detected, retrying...');
return retryOperation();
} else if (VError.hasCauseWithName(err, 'AuthenticationError')) {
console.log('Auth issue detected, redirecting to login...');
return redirectToLogin();
} else {
console.log('Unknown error type');
throw err;
}
}Retrieves the complete stack trace including all errors in the cause chain.
/**
* Get full stack trace including all causes in the chain
* @param {Error} err - Error to get stack from (must be an Error instance)
* @returns {string} Complete stack trace with all causes
*/
VError.fullStack(err);Usage Examples:
const VError = require('verror');
const originalError = new Error('file not found');
const chainedError = new VError(originalError, 'failed to read config');
const topError = new VError(chainedError, 'application startup failed');
// Get full stack trace
const fullStack = VError.fullStack(topError);
console.log(fullStack);
// Outputs something like:
// Error: application startup failed: failed to read config: file not found
// at Object.<anonymous> (/path/to/file.js:3:19)
// ... stack frames for topError
// caused by: VError: failed to read config: file not found
// at Object.<anonymous> (/path/to/file.js:2:21)
// ... stack frames for chainedError
// caused by: Error: file not found
// at Object.<anonymous> (/path/to/file.js:1:23)
// ... stack frames for originalError
// Compare with regular stack (only shows top error)
console.log(topError.stack);
// Only shows stack for topError, not the causesConverts an array of errors into a single error, using MultiError for multiple errors or returning the single error directly.
/**
* Convert array of errors to single error
* @param {Error[]} errors - Array of Error objects
* @returns {Error|MultiError|null} Single error, MultiError for multiple, or null if empty
*/
VError.errorFromList(errors);Usage Examples:
const VError = require('verror');
// Empty array
console.log(VError.errorFromList([])); // null
// Single error
const singleError = new Error('single issue');
const result1 = VError.errorFromList([singleError]);
console.log(result1 === singleError); // true (returns the error directly)
// Multiple errors
const errors = [
new Error('validation failed for email'),
new Error('validation failed for age'),
new Error('validation failed for name')
];
const result2 = VError.errorFromList(errors);
console.log(result2 instanceof VError.MultiError); // true
console.log(result2.message); // "first of 3 errors"
// Useful for parallel operations
async function validateAllFields(data) {
const validationResults = await Promise.allSettled([
validateEmail(data.email),
validateAge(data.age),
validateName(data.name)
]);
const errors = validationResults
.filter(result => result.status === 'rejected')
.map(result => result.reason);
const finalError = VError.errorFromList(errors);
if (finalError) {
throw finalError;
}
return data; // All validations passed
}Iterates over individual errors, automatically handling MultiError by calling the function for each contained error.
/**
* Iterate over individual errors (handles MultiError automatically)
* @param {Error} err - Error to iterate over (must be an Error instance)
* @param {Function} func - Function to call for each error
* @returns {undefined}
*/
VError.errorForEach(err, func);Usage Examples:
const VError = require('verror');
// Single error
const singleError = new Error('single issue');
VError.errorForEach(singleError, function(err) {
console.log('Error:', err.message);
});
// Output: "Error: single issue"
// MultiError
const multiError = new VError.MultiError([
new Error('validation failed for email'),
new Error('validation failed for age'),
new Error('validation failed for name')
]);
VError.errorForEach(multiError, function(err) {
console.log('Validation error:', err.message);
});
// Output:
// "Validation error: validation failed for email"
// "Validation error: validation failed for age"
// "Validation error: validation failed for name"
// Useful for logging all errors
function logAllErrors(err) {
VError.errorForEach(err, function(individualError) {
logger.error({
message: individualError.message,
stack: individualError.stack,
name: individualError.name
});
});
}
// Useful for collecting error details
function collectErrorMessages(err) {
const messages = [];
VError.errorForEach(err, function(individualError) {
messages.push(individualError.message);
});
return messages;
}
const multiError = new VError.MultiError([
new Error('error 1'),
new Error('error 2')
]);
console.log(collectErrorMessages(multiError)); // ['error 1', 'error 2']Common patterns for using the static utility methods together:
/**
* Common utility patterns:
*
* Error Analysis: Use cause(), info(), findCauseByName() to analyze errors
* Error Reporting: Use fullStack() for detailed logging
* Multi-Error Handling: Use errorFromList(), errorForEach() for parallel operations
* Error Classification: Use hasCauseWithName() for conditional handling
*/Usage Examples:
const VError = require('verror');
// Comprehensive error analysis
function analyzeError(err) {
console.log('Error analysis:');
console.log('- Message:', err.message);
console.log('- Name:', err.name);
const cause = VError.cause(err);
if (cause) {
console.log('- Has cause:', cause.message);
}
const info = VError.info(err);
if (Object.keys(info).length > 0) {
console.log('- Info:', JSON.stringify(info, null, 2));
}
console.log('- Full stack:', VError.fullStack(err));
}
// Error handling middleware
function errorHandler(err) {
// Log all individual errors
VError.errorForEach(err, function(individualError) {
logger.error({
message: individualError.message,
stack: individualError.stack
});
});
// Check for specific error types
if (VError.hasCauseWithName(err, 'DatabaseError')) {
return { status: 503, message: 'Service temporarily unavailable' };
} else if (VError.hasCauseWithName(err, 'ValidationError')) {
return { status: 400, message: 'Invalid request data' };
} else {
return { status: 500, message: 'Internal server error' };
}
}
// Parallel operation error aggregation
async function processMultipleItems(items) {
const results = await Promise.allSettled(
items.map(item => processItem(item))
);
const errors = results
.filter(result => result.status === 'rejected')
.map(result => result.reason);
const aggregatedError = VError.errorFromList(errors);
if (aggregatedError) {
// Add context to the aggregated error
throw new VError(aggregatedError, 'failed to process %d items', items.length);
}
return results.map(result => result.value);
}Install with Tessl CLI
npx tessl i tessl/npm-verror