API Reference
Complete API reference for all exports from @deessejs/errors.
This page documents all public exports from @deessejs/errors.
error()
Creates an error factory function for defining typed, structured errors.
const errorFactory = error<TFields>(config)There are two public overloads:
- No-schema overload:
error<T>({ name, message?, inherits? }). The call signature accepts no arguments (or an empty object) whenTis the empty shape; otherwise the input argument is required. - Schema overload:
error({ name, fields, message, inherits? }). The factory's call signature requires the schema'sInferInputas the argument. A function-formmessageis required; a stringmessageis not accepted alongside a schema.
Parameters
| Parameter | Type | Description |
|---|---|---|
| config.name | string | Error name identifier (required) |
| config.message | string or function | String template (legacy, {field} placeholders) or (data) => string taking the validated (post-transform) fields. Required to be a function when a schema is supplied. |
| config.fields | StandardSchemaV1 | Field validation schema (Zod, Valibot, ArkType, etc.). The schema's output must be a non-null, non-array object — see Fields and Schema. |
| config.inherits | ErrorFactory or ErrorFactory[] | Parent error(s) to inherit from. The leaf's InferOutput must be assignable to every parent's InferOutput (enforced at the call site by the contravariance witness). |
When fields is supplied, the input is validated against the schema at every call. Invalid inputs throw an ArgsValidationError. When message is a function, it receives the parsed (post-transform) data as its argument.
Returns
An ErrorFactory function that creates error instances. The factory has these properties:
| Property | Type | Description |
|---|---|---|
| name | string | The error name |
| inherits | ErrorFactory or ErrorFactory[] or undefined | Parent error types |
| schema | StandardSchemaV1 or undefined | The validation schema (exposed via the factory) |
| rawMessage | string or function or undefined | Original message template (string) or function, set when message is supplied |
Example
import { z } from "zod";
import { error } from "@deessejs/errors";
const AppError = error({ name: "AppError" });
const ValidationError = error({
name: "ValidationError",
fields: z.object({ field: z.string() }),
message: (data) => `Field "${data.field}" is invalid`,
inherits: AppError,
});
const err = ValidationError({ field: "email" });raise()
Throws an error instance. The primary mechanism for throwing errors in @deessejs/errors.
raise(error: ErrorInstance): neverParameters
| Parameter | Type | Description |
|---|---|---|
| error | ErrorInstance | The error to throw |
Returns
never - this function always throws.
Example
import { error, raise, is } from "@deessejs/errors";
const ValidationError = error({ name: "ValidationError" });
try {
// The no-schema factory takes no arguments.
raise(ValidationError());
} catch (err) {
console.log(is(err, ValidationError)); // -> true
}is()
Type guard function to check if an error is an instance of a specific error type. Two overloads are exposed:
- Factory overload:
is(error, factory)narrows the input toErrorInstance<ExtractFactoryFields<typeof factory>>. The walk traverses the factory'sinheritsgraph (depth-first, with cycle detection) and consults the package-privateINSTANCE_REGISTRYto reject foreign objects that imitate the factory marker. - Native constructor overload:
is(error, NativeErrorClass)narrows the input toInstanceType<typeof NativeErrorClass>. A nativeErrorsubclass carries no.fields,.notes,.from(), or.addNote()extensions.
is() is per-package-load: an instance created by a second copy of @deessejs/errors (a duplicate in node_modules, a separate bundle, a CommonJS/ESM dual load) is registered in that copy's internal registry, not ours. Holding a direct reference to its factory is not sufficient — the registry check fails, and is() returns false. To recognize cross-load instances, the consumer must call is() from the same load that produced the instance.
const result = is(error: unknown, ErrorType): error is ErrorInstanceParameters
| Parameter | Type | Description |
|---|---|---|
| error | unknown | The error to check |
| ErrorType | ErrorFactory or ErrorClass | The error type to check against |
Returns
boolean - true if the error matches or inherits from the type. Narrows the input type for TypeScript.
Example
import { error, is } from "@deessejs/errors";
const AppError = error({ name: "AppError" });
const ValidationError = error({
name: "ValidationError",
inherits: AppError,
});
// The no-schema factory has an empty input shape.
const err = ValidationError();
if (is(err, ValidationError)) {
console.log("ValidationError matched");
}
if (is(err, AppError)) {
console.log("AppError matched via inheritance");
}
// Native error discrimination works too.
try {
JSON.parse("invalid");
} catch (e) {
if (is(e, SyntaxError)) {
console.log("SyntaxError caught");
}
}causes()
Returns all causes in an error chain, ordered immediate cause first, root cause last. The walk follows each cause's own .cause link with cycle detection.
const chain = causes(error: unknown): Error[]Parameters
| Parameter | Type | Description |
|---|---|---|
| error | unknown | The error to get causes from |
Returns
Error[] - array of errors in the cause chain. Returns an empty array for null, undefined, or errors without causes. The returned array is a fresh copy; mutations do not affect the underlying error.
Example
import { error, causes } from "@deessejs/errors";
const AppError = error({ name: "AppError" });
const ValidationError = error({ name: "ValidationError" });
// Build the chain by attaching each cause to the previous one.
// The .from() call replaces the previous direct cause.
const root = new Error("Connection timeout");
const middle = ValidationError().from(root);
const appErr = AppError().from(middle);
const chain = causes(appErr);
console.log(chain.length); // 2 — [middle, root]ArgsValidationError
Thrown when input data fails a Standard Schema validator attached to fields. The error carries the original validator failure information, branded as an @deessejs/errors instance.
class ArgsValidationError extends ErrorConstructor
| Parameter | Type | Description |
|---|---|---|
| source | string | Name of the originating factory |
| issues | ReadonlyArray<StandardSchemaV1.Issue> | Read-only array of validator issues (per Standard Schema spec) |
| vendor | string | Vendor identifier (e.g. zod, valibot, arktype) |
Instance properties
| Property | Type | Description |
|---|---|---|
| source | string | The originating factory name |
| issues | ReadonlyArray<StandardSchemaV1.Issue> | Validator issues |
| vendor | string | Vendor identifier |
Message format
Argument validation failed for "<source>": see .issuesExample
import { z } from "zod";
import { error, ArgsValidationError } from "@deessejs/errors";
const ValidationError = error({
name: "ValidationError",
fields: z.object({ field: z.string().min(1) }),
message: (data) => "Field " + data.field,
});
try {
ValidationError({ field: "" });
} catch (err) {
if (err instanceof ArgsValidationError) {
console.log(err.vendor);
console.log(err.issues);
}
}ErrorInstance
The type of object returned by error factories. It extends the native Error type.
Properties
| Property | Type | Description |
|---|---|---|
| name | string | Error name identifier |
| message | string | Human-readable error message |
| stack | string | Stack trace string |
| fields | T | Validated (post-transform) fields, or the empty record for the no-schema form |
| notes | string[] | Additional notes (PEP 678) |
| cause | Error or null | Direct cause of this error. Each .from() call replaces the previous cause; the previous cause is reachable through its own .cause link. Use the top-level causes() function to walk the full chain. |
| context | Record<string, unknown> or null | Injected context data |
| inherits | ErrorFactory or ErrorFactory[] or undefined | Parent error factories (frozen snapshot taken at construction) |
Methods
| Method | Description |
|---|---|
| from(cause: Error or ErrorInstance) | Chains a cause error to this error. Replaces the previous direct cause. Returns this for chaining. |
| addNote(note: string) | Appends a runtime context note (PEP 678). Returns this for chaining. |
See Also
Error Factory
Create custom error types.
Type Checking
Use is() for type guards.
Exception Chaining
Chain errors with from().
Fields and Schema
Field validation with Standard Schema.
Constraints
The package's contracts depend on a few consumer-side guarantees. Each is enforced at the boundary that owns it; understanding them helps avoid footguns.
TypeScript
strictFunctionTypes is required. The contravariance witness
that enforces inheritance compatibility relies on function
parameters being checked contravariantly. Without
strictFunctionTypes, the inheritance constraint is bypassed at
compile time. strictFunctionTypes is enabled by strict, which
is on in this project's tsconfig.
TypeScript 5.4 or later. The public error() overloads use
NoInfer<T>, which was introduced in TypeScript 5.4. Earlier
versions compile but lose the NoInfer semantics on the T
parameter.
Schemas
Output must be a non-null, non-array object. A schema whose
InferOutput is null, an unknown[], a primitive, or
undefined is rejected at compile time via the
fields: S & (IsObjectOutput<InferOutput<S>> extends true ? unknown : never)
intersection, and at runtime via the isObjectFields guard that
throws ArgsValidationError if the schema's value is malformed.
Schemas must be synchronous. A schema whose validate
returns a Promise is rejected with ArgsValidationError. The
Promise is still attached and a no-op .catch is added so a
late rejection cannot surface as an unhandledRejection.
Input is required when a schema is supplied. A factory
declared with a Standard Schema refuses a no-arg call at compile
time. The runtime also throws a localized TypeError for the
schema-bearing path so consumers who bypass the type-checker
still get a clear message. This applies even when the schema
accepts the empty shape (z.object({})).
.fields carries the post-transform output. For schemas
that transform (e.g. z.coerce, z.default, z.transform),
the leaf's .fields is the schema's InferOutput, not the
InferInput. The factory's message function receives the
post-transform output.
is() and the instance registry
is() is per-package-load. An instance created by a second
copy of @deessejs/errors (a duplicate in node_modules, a
separate bundle, a CommonJS/ESM dual load, two copies in a
micro-frontend) is registered in that copy's internal
INSTANCE_REGISTRY (a WeakSet), not ours. Holding a direct
reference to its factory is not sufficient: the marker slot is
read and matches, but the registry check fails, and is()
returns false. To recognize cross-load instances, the consumer
must call is() from the same load that produced the instance.
The instance marker is non-writable on real instances. Set
via Object.defineProperty with writable: false. A foreign
object that imitates the marker is rejected by the registry
check; a hostile object that re-defines the marker on a real
instance is rejected in strict mode (the assignment throws) and
silently fails in sloppy mode (the marker is unchanged).
Inheritance
The factory's inherits slot is a frozen snapshot. Built
once at construction, before the closure, and used for both the
factory's metadata and every produced instance's inherits.
The caller's array is not mutated in place; classification
is preserved across caller-side mutations on the original list.
Each factory runs its own schema. Inheritance is a static
type-level relationship plus a recognition walk for is(). The
parent schema does not validate the child's data at
instantiation. Consumers who relied on the parent-schema cascade
to coerce a child field through a parent's transform must
compose the schema themselves.
Legacy deprecation
The string-template form (error({ name, message: 'Hello {name}' })) is deprecated in 2.0.0 and emits a one-time warning
per call site, only when the message is a string with
{field} placeholders, and only when
process.env.DEESSEJS_ERRORS_LEGACY_TEMPLATES is not '1'. A
plain string without placeholders and a function-form message
do not warn. The warning is suppressed in browser bundles
(process is read only when defined).