Error Instance
Understand the properties and methods available on error instances created by @deessejs/errors.
When you create an error using an error factory, you get an error instance. This instance extends the native JavaScript Error object with additional properties and methods specific to @deessejs/errors.
Standard Properties
Error instances include all standard Error properties:
import { error } from '@deessejs/errors';
const AppError = error({ name: 'AppError' });
const err = AppError();
console.log(err.name); // -> AppError
console.log(err.message); // -> AppError
console.log(typeof err.stack); // -> string
console.log(err instanceof Error); // -> trueThese properties behave exactly like native errors, so they work with all existing error handling code and tools.
The fields Property
The fields property carries the data the schema validated when the error was constructed. This is where you store structured context about what went wrong. A no-schema factory's fields is the empty object {}.
import { z } from 'zod';
import { error } from '@deessejs/errors';
const ValidationError = error({
name: 'ValidationError',
fields: z.object({ field: z.string(), value: z.unknown() }),
message: () => 'Invalid value',
});
const err = ValidationError({ field: 'email', value: 'not-an-email' });
console.log(err.fields.field); // -> email
console.log(err.fields.value); // -> not-an-emailThe fields object is typed by the schema's InferOutput, so TypeScript checks every property access.
The from() Method
The from() method chains another error as the cause of the current error. This is how you preserve the full context of what led to an error.
import { error, is, causes } from '@deessejs/errors';
const AppError = error({ name: 'AppError' });
const ValidationError = error({ name: 'ValidationError' });
const validationErr = ValidationError();
const appErr = AppError();
// Chain the validation error as a cause.
appErr.from(validationErr);
console.log(appErr.cause === validationErr); // -> true
// The full chain is reachable via the causes() helper, which
// walks the cause links and returns the chain immediate-cause first.
console.log(causes(appErr).length); // -> 1
// `is()` walks the inheritance graph; the type guard narrows
// `validationErr` to the same factory.
console.log(is(validationErr, ValidationError)); // -> trueThe from() method returns the error instance, allowing you to chain multiple calls or combine it with other operations.
The cause Property
The cause property holds the direct cause of the error — the error passed to the most recent from() call. Use is() to narrow it to a specific factory; the built-in instanceof checks against the native Error, not the factory marker.
import { error, is } from '@deessejs/errors';
const AppError = error({ name: 'AppError' });
const ValidationError = error({ name: 'ValidationError' });
const appErr = AppError();
appErr.from(ValidationError());
console.log(appErr.cause === null); // -> false
console.log(is(appErr.cause, ValidationError)); // -> trueWhen no cause has been set, cause is null.
The causes() helper
The causes() function returns the full chain of errors, ordered immediate cause first, root cause last. It walks the .cause link of each error in the chain, detects cycles, and accepts native Error and null/undefined (returns [] for those). It is a top-level function, not a property on the instance.
import { error, causes } from '@deessejs/errors';
const AppError = error({ name: 'AppError' });
const ValidationError = error({ name: 'ValidationError' });
// Build the chain: ValidationError -> DatabaseError -> AppError.
const databaseErr = new Error('Database connection failed');
const validationErr = ValidationError().from(databaseErr);
const appErr = AppError().from(validationErr);
// Walk the chain via causes() — immediate cause first, root cause last.
const chain = causes(appErr);
console.log(chain.length); // -> 2
console.log(chain[0].name); // -> ValidationError
console.log(chain[1].message); // -> Database connection failedWhen you chain multiple errors, the new cause replaces the direct cause; the previous cause becomes the second link in the chain, keeping causal order.
The notes Property
The notes property lets you attach additional context to an error after it is created. Each addNote() call returns this for chaining, and the runtime maintains the notes array in the order the calls were made.
import { error } from '@deessejs/errors';
const AppError = error({ name: 'AppError' });
const err = AppError();
// Add context notes
err.addNote('Caught in user controller');
err.addNote('User ID was usr_123');
console.log(err.notes[0]); // -> Caught in user controller
console.log(err.notes[1]); // -> User ID was usr_123Notes are stored as a readonly array of strings. To add notes, use addNote() rather than notes.push(); the notes slot is a snapshot and is replaced on each addNote() call.
The context Property
The context property holds additional data injected into the error. It is null by default and is meant to be set at construction time when an error needs to carry auxiliary data the schema doesn't cover.
import { error } from '@deessejs/errors';
const AppError = error({ name: 'AppError' });
const err = AppError();
console.log(err.context); // -> nullWhen no context has been set, context is null. To inject structured context, prefer carrying it through your factory's own schema and the fields slot — that keeps the data flow type-checked end to end.