@fwoom/error
v1.0.0
Published
A small error utility for creating consistent, safe, and portable application errors.
Maintainers
Readme
@fwoom/error
A small, framework-agnostic error utility for JavaScript and TypeScript applications.
@fwoom/error is designed to be simple, safe by default, and portable. It helps you create consistent, structured errors without forcing class-based inheritance or framework-specific concepts.
Installation
npm install @fwoom/errorCore Concepts
Errors are data
Errors are identified by a stable error code, not by instanceof checks or class inheritance.
This makes errors:
- Portable across runtimes
- Serializable
- Safe to handle in distributed systems
Public API
@fwoom/error intentionally exposes only two main APIs:
defineError()– define an error type and get a reusable factorycreateError()– create an error by code (zero-config fallback)
In addition, it exports a small set of standard error factories.
Defining Custom Errors
Use defineError to declare an error type and its defaults. This is usually done once and exported.
import { defineError } from "@fwoom/error";
export const userNotFound = defineError({
code: "USER_NOT_FOUND",
status: 404,
expose: true,
message: "User not found",
});defineError:
- Registers error metadata
- Returns a callable error factory
- Is safe to import anywhere (module runs once)
Using Error Factories
The returned factory is what you throw at runtime.
Message only
throw userNotFound("User not found");Message with details
throw userNotFound("User not found", { userId: 123 });Override options
throw userNotFound("User not found", {
status: 410,
expose: true,
details: { userId: 123 },
});createError (Zero-config usage)
createError lets you create errors by code without defining them first.
import { createError } from "@fwoom/error";
throw createError("SOMETHING_BROKE");With a custom message:
throw createError("NOT_FOUND", "User not found");With full options:
throw createError("CUSTOM_ERROR", {
message: "Something went wrong",
status: 400,
expose: false,
details: { reason: "invalid_state" },
});If the error code was not defined via defineError, a development-only warning is shown.
Standard Error Factories
@fwoom/error provides common HTTP-style errors out of the box.
import {
badRequest,
unauthorized,
forbidden,
notFound,
conflict,
unprocessableEntity,
internalError,
} from "@fwoom/error";Available standard errors
| Factory | Code | Status | Exposed | Default message |
| --------------------- | ---------------------- | ------ | ------- | -------------------- |
| badRequest | BAD_REQUEST | 400 | true | Bad request |
| unauthorized | UNAUTHORIZED | 401 | true | Unauthorized |
| forbidden | FORBIDDEN | 403 | true | Forbidden |
| notFound | NOT_FOUND | 404 | true | Not found |
| conflict | CONFLICT | 409 | true | Conflict |
| unprocessableEntity | UNPROCESSABLE_ENTITY | 422 | true | Unprocessable entity |
| internalError | INTERNAL_ERROR | 500 | false | Internal error |
Example:
throw notFound("User not found", { userId: 123 });Error Fields
All errors produced by this package share the same shape:
interface BaseError extends Error {
code: string;
message: string;
status?: number;
expose: boolean;
details?: unknown;
cause?: unknown;
}Defaults and Safety
statusdefaults to500exposedefaults tofalsemessagefalls back to the error code
This ensures that errors are safe by default, even in zero-config usage.
Development vs Production Behavior
Development
- Warns when
createErroris used with an undefined error code - Warns on duplicate
defineErrorcalls - Never throws because of misconfiguration
Production
- No warnings
- Same runtime behavior
- Safe messages only
Why no classes or instanceof
@fwoom/error intentionally avoids class-based errors.
Instead of:
if (err instanceof ValidationError) {
}Use:
if (err.code === "VALIDATION_FAILED") {
}This approach is:
- More portable
- Stable across package boundaries
- Safer in distributed systems
Philosophy
Errors should be:
- Explicit, not implicit
- Data-first, not inheritance-based
- Safe by default
- Easy to create, hard to misuse
