Rich JavaScript errors with printf-style messages, error chaining, and structured metadata
—
VError provides three additional specialized error classes beyond the main VError class: SError for strict printf interpretation, WError for wrapped error messages, and MultiError for handling multiple errors from parallel operations.
SError is identical to VError but enforces strict interpretation of printf-style arguments, throwing errors when null or undefined values are passed to printf specifiers instead of converting them to strings.
/**
* SError constructor - same signatures as VError with strict printf parsing
* @param {Error|Object|string} [causeOrOptionsOrMessage] - Cause error, options object, or message
* @param {...*} args - Printf-style arguments (strict interpretation)
*/
function SError(causeOrOptionsOrMessage, ...args);
// Inherits all VError properties and methods
// Name defaults to 'VError' (not 'SError') after constructionUsage Examples:
const VError = require('verror');
const SError = VError.SError;
// Valid usage
const err1 = new SError('user %s not found', 'john');
// This will throw an error (strict mode)
try {
const err2 = new SError('value is %s', null); // Throws error
} catch (e) {
console.log('SError rejected null value');
}
// Compare with VError (non-strict)
const VError = require('verror');
const err3 = new VError('value is %s', null); // Works, becomes "value is null"WError wraps errors while hiding lower-level error messages from the top-level error. The cause message is not appended to the main message, but the cause chain is preserved for debugging and the cause information appears in toString() output.
/**
* WError constructor that hides cause messages from main message
* @param {Error|Object|string} [causeOrOptionsOrMessage] - Cause error, options object, or message
* @param {...*} args - Printf-style arguments for message formatting
*/
function WError(causeOrOptionsOrMessage, ...args);
interface WErrorInstance extends VErrorInstance {
/** WError name */
name: 'WError';
}/**
* Custom toString that shows cause in "caused by" format
* @returns {string} Error string with cause information
*/
toString(): string;
/**
* Get or set the cause (historical compatibility method)
* @param {Error} [newCause] - Optional new cause to set
* @returns {Error} Current cause error
*/
cause(newCause?: Error): Error;Usage Examples:
const VError = require('verror');
const WError = VError.WError;
const originalError = new Error('database connection failed');
const wrappedError = new WError(originalError, 'user operation failed');
// Message only shows the wrapper message
console.log(wrappedError.message); // "user operation failed"
// But toString shows both
console.log(wrappedError.toString()); // "WError: user operation failed; caused by Error: database connection failed"
// Cause is still accessible
console.log(VError.cause(wrappedError) === originalError); // true
// Historical cause() method can get/set
console.log(wrappedError.cause() === originalError); // true
const newCause = new Error('different error');
wrappedError.cause(newCause);
console.log(wrappedError.cause() === newCause); // trueMultiError represents a collection of errors for consumers that generally only deal with one error. It encapsulates multiple errors but can be treated as a single error with a summary message.
/**
* MultiError constructor for handling multiple errors
* @param {Error[]} errors - Array of Error objects (at least 1 required)
*/
function MultiError(errors);
interface MultiErrorInstance extends VErrorInstance {
/** MultiError name */
name: 'MultiError';
/** Internal errors array */
ase_errors: Error[];
}/**
* Returns a copy of the errors array
* @returns {Error[]} Copy of all contained errors
*/
errors(): Error[];Usage Examples:
const VError = require('verror');
const MultiError = VError.MultiError;
// Create from multiple errors
const errors = [
new Error('validation failed for field "email"'),
new Error('validation failed for field "age"'),
new Error('validation failed for field "name"')
];
const multiError = new MultiError(errors);
console.log(multiError.message); // "first of 3 errors"
console.log(multiError.name); // "MultiError"
// Access individual errors
const individualErrors = multiError.errors();
console.log(individualErrors.length); // 3
console.log(individualErrors[0].message); // "validation failed for field "email""
// The first error becomes the cause
const VError = require('verror');
console.log(VError.cause(multiError) === errors[0]); // true
// Use with errorForEach utility
VError.errorForEach(multiError, function(err) {
console.log('Error:', err.message);
});
// Prints each individual error messageSummary of differences between the error classes:
/**
* Class behavior comparison:
*
* VError:
* - Default behavior, cause message appended to main message
* - Non-strict printf (null/undefined converted to strings)
* - Name: 'VError'
*
* SError:
* - Strict printf (null/undefined cause errors)
* - Otherwise identical to VError
* - Name: 'VError' (inherits from VError)
*
* WError:
* - Cause message NOT appended to main message
* - toString() shows cause in "caused by" format
* - Historical cause() method can set cause
* - Name: 'WError'
*
* MultiError:
* - Contains multiple errors
* - Summary message: "first of N error(s)"
* - First error becomes the cause
* - Name: 'MultiError'
*/Usage Examples:
const VError = require('verror');
const { SError, WError, MultiError } = VError;
const originalError = new Error('underlying issue');
// VError: cause message included
const vErr = new VError(originalError, 'operation failed');
console.log(vErr.message); // "operation failed: underlying issue"
// WError: cause message hidden
const wErr = new WError(originalError, 'operation failed');
console.log(wErr.message); // "operation failed"
console.log(wErr.toString()); // "WError: operation failed; caused by Error: underlying issue"
// SError: strict printf
const sErr = new SError('valid message with %s', 'string'); // OK
// const sErr2 = new SError('invalid %s', null); // Would throw
// MultiError: multiple errors
const multi = new MultiError([
new Error('error 1'),
new Error('error 2')
]);
console.log(multi.message); // "first of 2 errors"Typical usage patterns for different error classes:
/**
* Common usage patterns:
*
* VError: General error chaining, preserving all context
* SError: When you want strict validation of printf arguments
* WError: API endpoints where internal errors should be hidden
* MultiError: Parallel operations that may generate multiple errors
*/Usage Examples:
// VError: Server-side error chaining
function readConfigFile(filename) {
return fs.readFile(filename).catch(err => {
throw new VError(err, 'failed to read config file "%s"', filename);
});
}
// WError: API error wrapping (hide internal details)
app.get('/api/users', async (req, res) => {
try {
const users = await getUsersFromDatabase();
res.json(users);
} catch (dbError) {
const apiError = new WError(dbError, 'failed to retrieve users');
res.status(500).json({ error: apiError.message }); // Only shows "failed to retrieve users"
logger.error(apiError.toString()); // Logs full cause chain
}
});
// MultiError: Parallel validation
async function validateUserData(userData) {
const validationPromises = [
validateEmail(userData.email),
validateAge(userData.age),
validateName(userData.name)
];
const results = await Promise.allSettled(validationPromises);
const errors = results
.filter(result => result.status === 'rejected')
.map(result => result.reason);
if (errors.length > 0) {
throw new MultiError(errors);
}
}Install with Tessl CLI
npx tessl i tessl/npm-verror