[](https://www.npmjs.com/package/@simpill/errors.utils) [](https://github.com/SkinnnyJay/simpill-utils/tree/main/utils/@simpill-errors.utils)
npm
npm install @simpill/errors.utilsGitHub (from monorepo)
git clone https://github.com/SkinnnyJay/simpill-utils.git && cd simpill-utils/utils/@simpill-errors.utils && npm install && npm run buildThen in your project: npm install /path/to/simpill-utils/utils/@simpill-errors.utils or npm link from that directory.
import { AppError, serializeError } from "@simpill/errors.utils";
const err = new AppError("Not found", {
code: "NOT_FOUND",
meta: { id: 123 },
});
const serialized = serializeError(err, { includeStack: false });| Feature | Description |
|---|---|
| AppError | Error with code, message, meta, cause (native non-enumerable semantics), toJSON() |
| serializeError | Always-JSON-safe serialization: circular meta/cause handled, AggregateError errors, extra props preserved |
| deserializeError | Rebuild an Error from a SerializedError (reverse of serializeError) |
| createErrorCodeMap / createErrorFromCode | Map codes to messages and construct AppError from a code |
| httpStatusFromCode / errorCodeFromStatus | Bidirectional ErrorCode ↔ HTTP status mapping |
| toProblemDetails | RFC 9457 application/problem+json responses (never leaks stack/cause) |
| isError / isErrorLike / isAppError | Cross-realm-safe error detection (native Error.isError when available) |
| sanitizeForJson | Deep-sanitize any value so JSON.stringify never throws |
import { ... } from "@simpill/errors.utils"; // Everything
import { ... } from "@simpill/errors.utils/client"; // Client
import { ... } from "@simpill/errors.utils/server"; // Server
import { ... } from "@simpill/errors.utils/shared"; // Shared only- AppError(message, options?) — options: code, meta, cause (native
Error.cause-style chaining) - AppErrorMeta — record for metadata (keep serializable; avoid circular references)
- serializeError(error, options?) → SerializedError — options: includeStack, includeCause, maxCauseDepth. The result is always safe to
JSON.stringify: circular references in meta, cause chains, or extra props are cycle-detected and replaced with"[Circular]"; bigint/symbol/function/Date/Map/Set are converted to JSON-safe forms. AggregateError innererrorsare serialized. Extra own enumerable properties (Node'serrno/syscall/path, custom fields) are preserved underprops. Error-like objects (name+message, e.g. cross-realm or postMessage payloads) keep their identity; thrown primitives keep their value inmessage; other values are attached as sanitizeddata. - SerializedError — name, message, code?, meta?, stack?, cause?, errors?, props?, data?
- deserializeError(serialized) → Error — restores name, message, stack, code, meta, cause chain, and inner errors
- isError / isErrorLike / isAppError — cross-realm-safe detection (uses native
Error.isErrorwhen available) - sanitizeForJson(value, maxDepth?) — deep-sanitize any value to a JSON-stringify-safe form
- createErrorCodeMap, createErrorFromCode, ERROR_CODES, ErrorCode, ErrorCodeOptions
- HTTP_STATUS_BY_CODE, httpStatusFromCode(code, fallback?), errorCodeFromStatus(status)
- toProblemDetails(error, options?) → ProblemDetails (RFC 9457), PROBLEM_JSON_CONTENT_TYPE
import { AppError, serializeError } from "@simpill/errors.utils";
const root = new Error("DB connection failed");
const err = new AppError("User load failed", {
code: "USER_LOAD",
meta: { userId: 42 },
cause: root,
});
console.log(serializeError(err, { includeStack: true }));
// Serialize cause separately: serializeError(err.cause)Pass serializeError(err, { includeStack: true }) to your logger (e.g. @simpill/logger.utils) so error fields are structured. Avoid logging raw Error objects in JSON formatters; use serializeError for consistent shape.
- serialize-error (npm): similar plain-object serialization; this package aligns with AppError (code, meta).
- http-errors: provides HTTP status codes and factory constructors; use AppError for domain errors and map code → status in your API layer if needed.
Built in: HTTP_STATUS_BY_CODE maps every ErrorCode to a status (NOT_FOUND → 404, VALIDATION → 422, TIMEOUT → 504, ...). Use httpStatusFromCode(code) / errorCodeFromStatus(status) for the two directions, and toProblemDetails(err, { instance: req.path }) to build an RFC 9457 application/problem+json body that never leaks stacks or causes: res.status(problem.status).type(PROBLEM_JSON_CONTENT_TYPE).json(problem).
This package does not define Result types. Use @simpill/patterns.utils: toResult(promise, mapError) and fromPromise(fn, mapError) return Promise<Result<T, AppError>> with mapError defaulting to wrapping unknown errors as AppError. Use @simpill/resilience.utils retryResult for retry that returns Result<T, AppError> instead of throwing.
There is no fromUnknown(e) export. To turn an unknown caught value into AppError: if (e instanceof AppError) return e; if (e instanceof Error) return new AppError(e.message, { code: ERROR_CODES.INTERNAL, cause: e }); return new AppError(String(e), { code: ERROR_CODES.INTERNAL });. patterns.utils fromThrowable + err(e) gives Result<never, unknown>; use toResult/ fromPromise with a mapError that does the above for AppError.
ERROR_CODES is a flat object (BAD_REQUEST, NOT_FOUND, etc.). For namespacing (e.g. AUTH.FORBIDDEN, USER.NOT_FOUND), use string code values with a prefix when creating AppError, or maintain separate code maps per domain and pass the code string. createErrorCodeMap accepts Partial<Record<ErrorCode, string>>; for custom codes use a broader type or a second map for extended codes.
- Result types — Use @simpill/patterns.utils (toResult, fromPromise) with mapError that returns AppError.
- fromUnknown — No helper; wrap unknown caught values in AppError manually (e.g.
instanceof Error→ use message and cause; else AppError(String(e))). - Namespaced error codes — ERROR_CODES is flat; use string prefixes (e.g.
"AUTH.FORBIDDEN") or separate code maps per domain.
| Use case | Recommendation |
|---|---|
| Domain/API errors with code and meta | Use AppError with ERROR_CODES and meta; serialize with serializeError for logs or responses. |
| Map error to HTTP status | Use httpStatusFromCode / toProblemDetails (RFC 9457) — built in. |
| Turn thrown/unknown into Result | Use patterns.utils fromPromise/ toResult with mapError that returns AppError. |
| Consistent error messages | Use createErrorCodeMap and use the map when creating or displaying errors. |
npx ts-node examples/01-basic-usage.ts| Example | Description |
|---|---|
| 01-basic-usage.ts | AppError, serializeError |
- CONTRIBUTING — Monorepo package guide.
ISC