CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-verror

Rich JavaScript errors with printf-style messages, error chaining, and structured metadata

Pending
Overview
Eval results
Files

error-classes.mddocs/

Error Classes

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.

Capabilities

SError Class

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 construction

Usage 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 Class

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';
}

WError Instance Methods

/**
 * 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); // true

MultiError Class

MultiError 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[];
}

MultiError Instance Methods

/**
 * 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 message

Error Class Comparison

Summary 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"

Common Patterns

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

docs

error-classes.md

index.md

static-utilities.md

verror-class.md

tile.json