DeesseJS Errors

Error Factory

Create custom error types with the error() function in @deessejs/errors.

The error() function is the primary way to define error types in @deessejs/errors. It returns a factory function that creates error instances with your specified configuration.

Basic Usage

At minimum, an error factory requires a name. This name identifies the error type and appears in the name property of instances.

basic.ts
import { error } from "@deessejs/errors";

const NotFoundError = error({
  name: "NotFoundError",
});

// The no-schema factory takes no arguments.
const err = NotFoundError();
console.log(err.name); // -> NotFoundError
console.log(err.message); // -> NotFoundError

When you provide only a name, the message defaults to the name. This is useful for simple errors where the name itself is descriptive enough.

Custom Messages

A message function takes the validated fields and returns the final string. The function form is the only path supported alongside a schema; the no-schema form also accepts a function so the page presents a single shape.

custom-message.ts
import { error } from "@deessejs/errors";

const ValidationError = error({
  name: "ValidationError",
  message: () => "Validation failed",
});

const err = ValidationError();
console.log(err.message); // -> Validation failed

Creating Instances with Fields

The real power of error factories comes from attaching structured data. With a Standard Schema, the leaf's fields are typed by InferOutput and validated at every call.

with-fields.ts
import { error } from "@deessejs/errors";
import { z } from "zod";

const UserError = error({
  name: "UserError",
  fields: z.object({ userId: z.string(), reason: z.string() }),
  message: (data) => `User ${data.userId}: ${data.reason}`,
});

const err = UserError({ userId: "usr_123", reason: "not found" });
console.log(err.fields.userId); // -> usr_123
console.log(err.fields.reason); // -> not found

The fields object is fully accessible on the instance — useful for logging, error monitoring, and tooling.

Using Fields with Schema Validation

For robust error definitions, attach a Standard Schema validator (Zod, Valibot, ArkType, etc.). Inputs are validated at creation time and invalid inputs throw an ArgsValidationError:

with-schema.ts
import { z } from "zod";
import { error } from "@deessejs/errors";

const ValidationError = error({
  name: "ValidationError",
  fields: z.object({
    field: z.string(),
    reason: z.string(),
  }),
  message: (data) => `Field "${data.field}" is invalid: ${data.reason}`,
});

const err = ValidationError({ field: "email", reason: "invalid format" });
console.log(err.message); // -> Field "email" is invalid: invalid format

See Fields and Schema for the full breakdown, including vendor-neutral coverage of Zod, Valibot, and ArkType.

Factory Properties

The function returned by error() has several useful properties attached to it:

properties.ts
import { error } from "@deessejs/errors";

const AppError = error({ name: "AppError" });

console.log(AppError.name); // -> AppError
console.log(AppError.inherits); // -> undefined

The inherits property exposes the parent factory or array of factories, which is() consults when checking inheritance. The instance carries the validated fields shape and the parent relationships for introspection.

Reusing Error Factories

Error factories are designed to be created once and reused throughout your application. Define them at module level so they are available everywhere:

definitions.ts
import { error } from "@deessejs/errors";
import { z } from "zod";

const NotFoundError = error({
  name: "NotFoundError",
  message: () => "Resource not found",
});

const ValidationError = error({
  name: "ValidationError",
  fields: z.object({ field: z.string(), reason: z.string() }),
  message: (data) => `Field ${data.field}: ${data.reason}`,
});

const NetworkError = error({
  name: "NetworkError",
  message: () => "Network request failed",
});

Then import and use them wherever needed:

usage.ts
import { error, raise, is } from "@deessejs/errors";

const NotFoundError = error({ name: "NotFoundError" });

try {
  raise(NotFoundError());
} catch (err) {
  if (is(err, NotFoundError)) {
    console.log(err.name); // -> NotFoundError
  }
}

See Also

On this page